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
Vuex mutations are essentially events: each mutation has a **name** and a **handler**. The handler function will receive the state as the first argument:
3
+
The only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string **type** and a **handler**. The handler function is where we perform actual state modifications, and it will receive the state as the first argument:
4
4
5
5
```js
6
6
conststore=newVuex.Store({
7
7
state: {
8
8
count:1
9
9
},
10
10
mutations: {
11
-
INCREMENT (state) {
11
+
increment (state) {
12
12
// mutate state
13
13
state.count++
14
14
}
15
15
}
16
16
})
17
17
```
18
18
19
-
Using all caps for mutation names is just a convention to make it easier to differentiate them from plain functions.
20
-
21
-
You cannot directly call a mutation handler. The options here is more like event registration: "When an `INCREMENT` event is dispatched, call this handler." To invoke a mutation handler, you need to dispatch a mutation event:
19
+
You cannot directly call a mutation handler. The options here is more like event registration: "When a mutation with type `increment` is triggered, call this handler." To invoke a mutation handler, you need to call **store.commit** with its type:
22
20
23
21
```js
24
-
store.dispatch('INCREMENT')
22
+
store.commit('increment')
25
23
```
26
24
27
-
### Dispatch with Arguments
25
+
### Commit with Payload
28
26
29
-
It is also possible to pass along arguments:
27
+
You can pass an additional argument to `store.commit`, which is called the **payload** for the mutation:
30
28
31
29
```js
32
30
// ...
33
31
mutations: {
34
-
INCREMENT (state, n) {
32
+
increment (state, n) {
35
33
state.count+= n
36
34
}
37
35
}
38
36
```
39
37
```js
40
-
store.dispatch('INCREMENT', 10)
38
+
store.commit('INCREMENT', 10)
41
39
```
42
40
43
-
Here `10` will be passed to the mutation handler as the second argument following `state`. Same for any additional arguments. These arguments are called the **payload** for the given mutation.
41
+
In most cases, the payload should be an object so that it can contain multiple fields, and the recorded mutation will also be more descriptive:
42
+
43
+
```js
44
+
// ...
45
+
mutations: {
46
+
increment (state, payload) {
47
+
state.count+=payload.amount
48
+
}
49
+
}
50
+
```
51
+
```js
52
+
store.commit('increment', {
53
+
amount:10
54
+
})
55
+
```
44
56
45
-
### Object-Style Dispatch
57
+
### Object-Style Commit
46
58
47
-
You can also dispatch mutations using objects:
59
+
An alternative way to commit a mutation is by directly using an object that has a `type` property:
48
60
49
61
```js
50
-
store.dispatch({
51
-
type:'INCREMENT',
52
-
payload:10
62
+
store.commit({
63
+
type:'increment',
64
+
amount:10
53
65
})
54
66
```
55
67
56
-
Note when using the object-style, you should include all arguments as properties on the dispatched object. The entire object will be passed as the second argument to mutation handlers:
68
+
When using object-style commit, the entire object will be passed as the payload to mutation handlers, so the handler remains the same:
57
69
58
70
```js
59
71
mutations: {
60
-
INCREMENT (state, mutation) {
61
-
state.count+=mutation.payload
72
+
INCREMENT (state, payload) {
73
+
state.count+=payload.amount
62
74
}
63
75
}
64
76
```
65
77
66
-
### Silent Dispatch
67
-
68
-
In some scenarios you may not want the plugins to record the state change. Multiple dispatches to the store in a short period or polled do not always need to be tracked. In these situations is may be considered appropriate to silence the mutations.
78
+
### Silent Commit
69
79
70
-
*Note:* This should be avoided where possible. Silent mutations break the contract of all state changes being tracked by the devtool. Use sparingly and where absolutely necessary.
80
+
> Note: This is a feature that will likely be deprecated once we implement mutation filtering in the devtools.
71
81
72
-
Dispatching without hitting plugins can be achieved with a `silent` flag.
82
+
By default, every committed mutation is sent to plugins (e.g. the devtools). However in some scenarios you may not want the plugins to record every state change. Multiple commits to the store in a short period or polled do not always need to be tracked. In such cases you can pass a third argument to `store.commit` to "silence" that specific mutation from plugins:
73
83
74
84
```js
75
-
/**
76
-
* Example: Progress action.
77
-
* Dispatches often for changes that are not necessary to be tracked
78
-
**/
79
-
exportfunctionstart(store, options= {}) {
80
-
let timer =setInterval(() => {
81
-
store.dispatch({
82
-
type:INCREMENT,
83
-
silent:true,
84
-
payload: {
85
-
amount:1,
86
-
},
87
-
});
88
-
if (store.state.progress===100) {
89
-
clearInterval(timer);
90
-
}
91
-
}, 10);
92
-
}
85
+
store.commit('increment', {
86
+
amount:1
87
+
}, { silent:true })
88
+
89
+
// with object-style dispatch
90
+
store.commit({
91
+
type:'increment',
92
+
amount:1
93
+
}, { silent:true })
93
94
```
94
95
95
96
### Mutations Follow Vue's Reactivity Rules
@@ -104,13 +105,13 @@ Since a Vuex store's state is made reactive by Vue, when we mutate the state, Vu
104
105
105
106
- Replace that Object with a fresh one. For example, using the stage-2 [object spread syntax](https://github.com/sebmarkbage/ecmascript-rest-spread) we can write it like this:
106
107
107
-
```js
108
-
state.obj= { ...state.obj, newProp:123 }
109
-
```
108
+
```js
109
+
state.obj= { ...state.obj, newProp:123 }
110
+
```
110
111
111
112
### Using Constants for Mutation Names
112
113
113
-
It is also common to use constants for mutation names - they allow the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application:
114
+
It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allow the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application:
114
115
115
116
``` js
116
117
// mutation-types.js
@@ -142,16 +143,24 @@ One important rule to remember is that **mutation handler functions must be sync
142
143
143
144
``` js
144
145
mutations: {
145
-
SOME_MUTATION (state) {
146
+
someMutation (state) {
146
147
api.callAsyncMethod(() => {
147
148
state.count++
148
149
})
149
150
}
150
151
}
151
152
```
152
153
153
-
Now imagine we are debugging the app and looking at our mutation logs. For every mutation logged, we want to be able to compare snapshots of the state *before* and *after*the mutation. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is dispatched, and we do not know when the callback will actually be called. Any state mutation performed in the callback is essentially un-trackable!
154
+
Now imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a "before" and "after" snapshots of the state. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called- any state mutation performed in the callback is essentially un-trackable!
154
155
155
156
### On to Actions
156
157
157
-
Asynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both with async callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, we perform all state mutations in a synchronous manner. We will perform all asynchronous operations inside [Actions](actions.md).
158
+
Asynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both withasync callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, **mutations are synchronous transactions**:
159
+
160
+
``` js
161
+
store.commit('increment')
162
+
// any state change that the "increment" mutation may cause
163
+
// should be done at this moment.
164
+
```
165
+
166
+
To handle asynchronous operations, let's introduce [Actions](actions.md).
0 commit comments