You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/en/structure.md
+54-52Lines changed: 54 additions & 52 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,17 +1,22 @@
1
1
# Application Structure
2
2
3
-
Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of opinions:
3
+
Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:
4
4
5
-
1. Application state lives in a single object.
6
-
2. Only mutation handlers can mutate the state.
7
-
3. Mutations must be synchronous, and the only side effects they produce should be state mutation.
8
-
4. All asynchronous logic such as data fetching should be performed in actions.
5
+
1. Application state is held in the store, as a single object.
9
6
10
-
The nice thing about Vuex actions and mutations is that **they are just functions**. As long as you follow these rules, it's up to you how to structure your project. The simplest Vuex instance can even be declared [in a single file](https://github.com/vuejs/vuex/blob/master/examples/counter/vuex.js)! However, this is unlikely to suffice for any serious project, so here are some recommended structures depending on the scale of your app.
7
+
2. The only way to mutate the state is by dispatching mutations on the store.
8
+
9
+
3. Mutations must be synchronous, and the only side effects they produce should be mutating the state.
10
+
11
+
4. We can expose a more expressive state mutation API by defining actions. Actions can encapsulate asynchronous logic such as data fetching, and the only side effects they produce should be dispatching mutations.
12
+
13
+
5. Components use getters to retrieve state from the store, and call actions to mutate the state.
14
+
15
+
The nice thing about Vuex mutations, actions and getters is that **they are all just functions**. As long as you follow these rules, it's up to you how to structure your project. However, it's nice to have some conventions so that you can instantly become familiar with another project that uses Vuex, so here are some recommended structures depending on the scale of your app.
11
16
12
17
### Simple Project
13
18
14
-
For a simple project, we can simply separate **actions** and **mutations**into respective files:
19
+
For a simple project, we can simply define the **store** and the **actions**in respective files:
15
20
16
21
```bash
17
22
.
@@ -20,17 +25,18 @@ For a simple project, we can simply separate **actions** and **mutations** into
20
25
├── components
21
26
│ ├── App.vue
22
27
│ └── ...
23
-
└── store
24
-
├── index.js # exports the vuex store
25
-
├── actions.js # exports all actions
26
-
└── mutations.js # exports all mutations
28
+
└── vuex
29
+
├── store.js # exports the store (with initial state and mutations)
30
+
└── actions.js # exports all actions
27
31
```
28
32
29
-
For an actual example, check out the [TodoMVC example](https://github.com/vuejs/vuex/tree/master/examples/todomvc).
33
+
For an actual example, check out the [Counter example](https://github.com/vuejs/vuex/tree/master/examples/counter) or the [TodoMVC example](https://github.com/vuejs/vuex/tree/master/examples/todomvc).
34
+
35
+
Alternatively, you can also split out mutations into its own file.
30
36
31
37
### Medium to Large Project
32
38
33
-
For any non-trivial app, we probably want to further split Vuex-related code into multiple "modules" (roughly comparable to "stores" in vanilla Flux), each dealing with a specific ___domain of our app. Each module would be managing a sub-tree of the state, exporting the initial state for that sub-tree and all mutations that operate on that sub-tree:
39
+
For any non-trivial app, we probably want to further split Vuex-related code into multiple "modules" (roughly comparable to "stores" in vanilla Flux, and "reducers" in Redux), each dealing with a specific ___domain of our app. Each module would be managing a sub-tree of the state, exporting the initial state for that sub-tree and all mutations that operate on that sub-tree:
34
40
35
41
```bash
36
42
├── index.html
@@ -40,75 +46,71 @@ For any non-trivial app, we probably want to further split Vuex-related code int
40
46
├── components
41
47
│ ├── App.vue
42
48
│ └── ...
43
-
└── store
44
-
├── actions.js # exports all actions
45
-
├── index.js
46
-
├── modules
47
-
│ ├── cart.js # state and mutations for cart
48
-
│└── products.js # state and mutations for products
49
-
└── mutation-types.js # constants
49
+
└── vuex
50
+
├── actions.js # exports all actions
51
+
├── store.js# where we assemble modules and export the store
52
+
├── mutation-types.js # constants
53
+
└── modules
54
+
├── cart.js # state and mutations for cart
55
+
└── products.js # state and mutations for products
// mutations can be an array of mutation definition objects
96
-
// from multiple modules
97
-
mutations: [cartMutations, productsMutations]
102
+
// combine sub modules
103
+
modules: {
104
+
cart,
105
+
products
106
+
}
98
107
})
99
108
```
100
109
101
-
Since all modules simply export objects and functions, they are quite easy to test and maintain. You are also free to alter the patterns used here to find a structure that fits your preference.
102
-
103
-
Note that we do not put actions into modules, because a single action may dispatch mutations that affect multiple modules. It's also a good idea to decouple actions from the state shape and the implementation details of mutations for better separation of concerns. If the actions file gets too large, we can turn it into a folder and split out the implementations of long async actions into individual files.
104
-
105
-
For an actual example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
110
+
Here, `cart` module's initial state will be attached to the root state tree as `store.state.cart`. In addition, **all the mutations defined in a sub-module only receives the sub-state-tree they are associated with**. So mutations defined in the `cart` module will receive `store.state.cart` as their first argument.
106
111
107
-
### Extracting Shared Computed Getters
112
+
Since all modules simply export objects and functions, they are quite easy to test and maintain, and can be hot-reloaded. You are also free to alter the patterns used here to find a structure that fits your preference.
108
113
109
-
In large projects, it's possible that multiple components will need the same computed property based on Vuex state. Since computed getters are just functions, you can split them out into a separate file so that they can be shared in any component via the store:
114
+
Note that we do not put actions into modules, because a single action may dispatch mutations that affect multiple modules. It's also a good idea to decouple actions from the state shape and the implementation details of mutations for better separation of concerns. If the actions file gets too large, we can turn it into a folder and split out the implementations of long async actions into individual files.
110
115
111
116
For an actual example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
112
-
For an actual example with hot reload API, check out the [Counter Hot Example](https://github.com/vuejs/vuex/tree/master/examples/counter-hot).
113
-
114
-
For more information, check out the [Getters documentation](getters.md)
0 commit comments