[DOC] store: add some basic documentation

This commit is contained in:
Géry Debongnie
2019-05-10 10:49:14 +02:00
parent 29cc94d567
commit d928927da8
2 changed files with 147 additions and 8 deletions
+3 -3
View File
@@ -351,7 +351,7 @@ We give here an informal description of the way components are created/updated
in an application. Here, ordered lists describe actions that are executed
sequentially, bullet lists describe actions that are executed in parallel.
**Scenario 1: Initial Mounting** Imagine we want to render the following component tree:
**Scenario 1: initial rendering** Imagine we want to render the following component tree:
```
A
@@ -391,7 +391,7 @@ component (with some code like `app.mount(document.body)`).
5. The method `mounted` is called recursively on all widgets in the following
order: `B`, `D`, `E`, `C`, `A`.
**Scenario 2: state change, rerendering**. Now, let's assume that the user clicked on some
**Scenario 2: rerendering a component**. Now, let's assume that the user clicked on some
button in `C`, and this results in a state update, which is supposed to:
- update `D`,
@@ -428,6 +428,6 @@ Here is what Owl will do:
2. `willUnmount` hook on `E`, then destruction of `E`,
3. (initial) patching of `F`, then hook `mounted` is called on `F`
5. patching of `D`,
5. patching of `D`
6. `patched` hooks are called on `D`, `C`
+144 -5
View File
@@ -1,8 +1,147 @@
# 🦉 Store 🦉
Managing the state in an application is not an easy task. Many different
architectures/designs/systems/... have been created. We propose here to use
the idea of a central store.
## Content
- Store
- connect
- [Overview](#overview)
- [Example](#example)
- [Reference](#reference)
- [Public API](#public-api)
- [Mutations](#mutations)
- [Actions](#actions)
- [Getters](#getters)
- [Connecting a component](#connecting-a-component)
## Overview
Managing the state in an application is not an easy task. In some cases, the
state of an application can be part of the component tree, in a natural way.
However, there are situations where some part of the state need to be displayed
in various parts of the user interface, and then, it is not obvious which
component should own which part of the state.
Owl's solution to this issue is a centralized store. It is a class that owns
some state, and let the developer update it in a structured way (through
mutations and actions). Owl components can then connect to the store, and will
be updated if necessary.
Note: Owl's store is inspired by React Redux and VueX.
## Example
Here is what a simple store look like:
```js
const actions = {
addTodo({commit}, message) {
commit('addTodo', message);
}
};
const mutations = {
addTodo({state}, message) {
const todo = {
id: state.nextId++,
message,
isCompleted: false,
};
state.todos.push(todo);
},
};
const state = {
todos: [],
nextId: 1,
};
const store = new owl.Store({state, actions, mutations});
store.on('update', () => console.log(store.state));
// updating the state
store.dispatch('addTodo', 'fix all bugs');
```
## Reference
The store is a simple `owl.EventBus` that triggers `update` events whenever its
state is changed. Note that these events are triggered only after a microtask
tick, so only one event will be triggered for any number of state changes in a
call stack.
Also, it is important to mention that the state is observed (with a `owl.Observer`),
which is the reason why it is able to know if it was changed. This implies that
state changes need to be done carefully in some cases (adding a new key to an
object, or modifying an array with the `arr[i] = newValue` syntax). See the
[Observer](observer.md)'s documentation for more details.
### Public API
1. `constructor`
2. `commit`
3. `dispatch`
### Mutations
Mutations are the only way to modify the state. Changing the state outside a
mutation is not allowed (and should throw an error). Mutations as synchronous.
### Actions
Actions are used to coordinate state changes. It is also useful whenever some
asynchronous logic is necessary. For example, fetching data should be done
in an action.
```js
const actions = {
login({commit}) {
commit('setLoginState', 'pending');
try {
const loginInfo = await doSomeRPC('/login/', 'someinfo');
commit('setLoginState', loginInfo);
} catch {
commit('setLoginState', 'error');
}
}
};
```
### Getters
Usually, data contained in the store will be stored in a normalized way. For
example,
```js
{
posts: [{id: 11, authorId: 4, content: 'Greetings'}],
authors: [{id: 4, name: 'John'}]
}
```
However, the user interface will probably need some denormalized data like
```js
{id: 11, author: {id: 4, name: 'John'}, content: 'Greetings'}
```
This is what `getters` are for: they give a centralized way to process and
transform the data contained in the store.
```js
const getters = {
getPost({state}) {
return function (id) {
const post = state.posts.find(p => p.id === id);
const author = state.authors.find(a => a.id = post.id);
return {
id,
author,
content: post.content
};
};
},
};
```
### Connecting a component
Todo