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
@@ -32,41 +32,27 @@ And here's the mutation handler:
32
32
```js
33
33
// ...
34
34
mutations: {
35
-
UPDATE_MESSAGE (state, message) {
35
+
updateMessage (state, message) {
36
36
state.obj.message= message
37
37
}
38
38
}
39
39
```
40
40
41
-
Admittedly, this is quite a bit more verbose than a simple `v-model`, but such is the cost of making state changes explicit and track-able. At the same time, do note that Vuex doesn't demand putting all your state inside a Vuex store - if you do not wish to track the mutations for form interactions at all, you can simply keep the form state outside of Vuex as component local state, which allows you to freely leverage `v-model`.
41
+
### Two-way Computed Property
42
42
43
-
Yet an alternative approach to leverage `v-model`with state in Vuex store is to use a computed property providing a setter in the component, with all the advantages of param attributes such as lazy, number and debounce.
43
+
Admittedly, the above is quite a bit more verbose than `v-model`+ local state, and we lose some of the useful features from `v-model` as well. An alternative approach is using a two-way computed property with a setter:
Copy file name to clipboardExpand all lines: docs/en/hot-reload.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -41,4 +41,4 @@ if (module.hot) {
41
41
}
42
42
```
43
43
44
-
You don't need to do anything specific for actions and getters. Webpack's hot module replacement system will "bubble" changes up the dependency chain - and changes in actions and getters will bubble up to the Vue components that imported them. Because Vue components loaded via `vue-loader` are automatically hot-reloadable, these affected components will hot-reload themselves and use the updated actions and getters.
44
+
Checkout the [counter-hot example](https://github.com/vuejs/vuex/tree/master/examples/counter-hot) to play with hot-reload.
Copy file name to clipboardExpand all lines: docs/en/plugins.md
+10-8Lines changed: 10 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -7,9 +7,7 @@ const myPlugin = store => {
7
7
// called when the store is initialized
8
8
store.subscribe((mutation, state) => {
9
9
// called after every mutation.
10
-
// The mutation comes in the format of { type, payload } for normal
11
-
// dispatches, and will be the original mutation object for object-style
12
-
// dispatches.
10
+
// The mutation comes in the format of { type, payload }.
13
11
})
14
12
}
15
13
```
@@ -23,17 +21,17 @@ const store = new Vuex.Store({
23
21
})
24
22
```
25
23
26
-
### Dispatching Inside Plugins
24
+
### Committing Mutations Inside Plugins
27
25
28
-
Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by dispatching mutations.
26
+
Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations.
29
27
30
-
By dispatching mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createPlugin` function can take some additional options for more complex tasks):
28
+
By committing mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createPlugin` function can take some additional options for more complex tasks):
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 is held in the store, as a single object.
5
+
1. Application-level state is centralized in the store.
6
6
7
-
2. The only way to mutate the state is by dispatching mutations on the store.
7
+
2. The only way to mutate the state is by committing **mutations**, which are synchronous transactions.
8
8
9
-
3.Mutations must be synchronous, and the only side effects they produce should be mutating the state.
9
+
3.Asynchronous logic should be encapsulated in, and can be composed with **actions**.
10
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.
11
+
As long as you follow these rules, it's up to you how to structure your project. If your store file gets too big, simply start splitting the actions, mutations and getters into separate files.
12
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.
16
-
17
-
### Simple Project
18
-
19
-
For a simple project, we can simply define the **store** and the **actions** in respective files:
20
-
21
-
```bash
22
-
.
23
-
├── index.html
24
-
├── main.js
25
-
├── components
26
-
│ ├── App.vue
27
-
│ └── ...
28
-
└── vuex
29
-
├── store.js # exports the store (with initial state and mutations)
30
-
└── actions.js # exports all actions
31
-
```
32
-
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.
36
-
37
-
### Medium to Large Project
38
-
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:
13
+
For any non-trivial app, we will likely need to leverage modules. Here's an example project structure:
40
14
41
15
```bash
42
16
├── index.html
@@ -46,91 +20,13 @@ For any non-trivial app, we probably want to further split Vuex-related code int
46
20
├── components
47
21
│ ├── App.vue
48
22
│ └── ...
49
-
└── vuex
50
-
├── actions.js # exports all actions
51
-
├── store.js # where we assemble modules and export the store
52
-
├── mutation-types.js # constants
23
+
└── store
24
+
├── index.js # where we assemble modules and export the store
25
+
├── actions.js # root actions
26
+
├── mutations.js # root mutations
53
27
└── modules
54
-
├── cart.js # state and mutations for cart
55
-
└── products.js # state and mutations for products
56
-
```
57
-
58
-
A typical module looks like this:
59
-
60
-
```js
61
-
// vuex/modules/products.js
62
-
import {
63
-
RECEIVE_PRODUCTS,
64
-
ADD_TO_CART
65
-
} from'../mutation-types'
66
-
67
-
// initial state
68
-
conststate= {
69
-
all: []
70
-
}
71
-
72
-
// mutations
73
-
constmutations= {
74
-
[RECEIVE_PRODUCTS] (state, products) {
75
-
state.all= products
76
-
},
77
-
78
-
[ADD_TO_CART] (state, productId) {
79
-
state.all.find(p=>p.id=== productId).inventory--
80
-
}
81
-
}
82
-
83
-
exportdefault {
84
-
state,
85
-
mutations
86
-
}
87
-
```
88
-
89
-
And in `vuex/store.js`, we "assemble" multiple modules together to create the Vuex instance:
90
-
91
-
```js
92
-
// vuex/store.js
93
-
importVuefrom'vue'
94
-
importVuexfrom'../../../src'
95
-
// import parts from modules
96
-
importcartfrom'./modules/cart'
97
-
importproductsfrom'./modules/products'
98
-
99
-
Vue.use(Vuex)
100
-
101
-
exportdefaultnewVuex.Store({
102
-
// combine sub modules
103
-
modules: {
104
-
cart,
105
-
products
106
-
}
107
-
})
28
+
├── cart.js # cart module
29
+
└── products.js # products module
108
30
```
109
31
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 receive the sub-state-tree they are associated with**. So mutations defined in the `cart` module will receive `store.state.cart` as their first argument.
111
-
112
-
The root of the sub-state-tree is irreplaceable inside the module itself. For example this won't work:
113
-
114
-
```js
115
-
constmutations= {
116
-
SOME_MUTATION (state) {
117
-
state = { ... }
118
-
}
119
-
}
120
-
```
121
-
122
-
Instead, always store actual state as a property of the sub-tree root:
123
-
124
-
```js
125
-
constmutations= {
126
-
SOME_MUTATION (state) {
127
-
state.value= { ... }
128
-
}
129
-
}
130
-
```
131
-
132
-
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.
133
-
134
-
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.
135
-
136
-
For an example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
32
+
As a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
0 commit comments