Skip to content

Commit d975e9d

Browse files
committed
Merge pull request vuejs#53 from blake-newman/feature/implement-getters-into-store
Feature/implement getters into store
2 parents b873ade + 9470089 commit d975e9d

File tree

15 files changed

+202
-53
lines changed

15 files changed

+202
-53
lines changed

docs/en/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [State](state.md)
66
- [Mutations](mutations.md)
77
- [Actions](actions.md)
8+
- [Getters](getters.md)
89
- [Data Flow](data-flow.md)
910
- [Application Structure](structure.md)
1011
- [Middlewares](middlewares.md)

docs/en/api.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const store = new Vuex.Store({ ...options })
1111
### Vuex.Store Constructor Options
1212

1313
- **state**
14-
14+
1515
- type: `Object`
1616

1717
The root state object for the Vuex store.
@@ -43,6 +43,19 @@ const store = new Vuex.Store({ ...options })
4343

4444
[Details](actions.md)
4545

46+
47+
- **getters**
48+
49+
- type: `Object | Array<Object>`
50+
51+
An object where each entry's key is the getter name and the value of a function which will receive the state as the first argument.
52+
53+
Vuex will process these entries and create the actual callable getter functions and expose them on the `getters` property of the store.
54+
55+
If passing in an Array of Objects, these objects will be automatically merged together into one final object.
56+
57+
[Details](getters.md)
58+
4659
- **middlewares**
4760

4861
- type: `Array<Object>`

docs/en/concepts.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ You can use the `Vuex.Store` constructor to create Vuex stores. In most cases, y
88

99
- **Actions**: Functions that dispatch mutations. An action can contain asynchronous operations and can dispatch multiple mutations.
1010

11+
- **Getters**: Functions that receive state to return a computed value. Useful for extracting shared computed functions from Vue components.
12+
1113
Why do we differentiate between *mutations* and *actions*, rather then just simple functions that manipulate the state however we want? The reason is because we want to **separate mutation and asynchronicity**. A lot of application complexity roots from the combination of the two. When separated, they both become easier to reason about and write tests for.
1214

1315
> If you are familiar with Flux, note there's a term/concept difference here: Vuex mutations are the equivalent of Flux **actions**, while Vuex actions are equivalent to Flux **action creators**.
@@ -24,8 +26,9 @@ import Vuex from 'vuex'
2426
const store = new Vuex.Store({
2527
state: { ... },
2628
actions: { ... },
27-
mutations: { ... }
29+
mutations: { ... },
30+
getters: { ... }
2831
})
2932
```
3033

31-
Once created, you can access the state via `store.state`, and the actions via `store.actions`. You cannot directly access the mutation functions - they can only be triggered by actions or calling `store.dispatch()`. We will discuss each concept in more details next.
34+
Once created, you can access the state via `store.state`, the actions via `store.actions` and the getters though `store.getters`. You cannot directly access the mutation functions - they can only be triggered by actions or calling `store.dispatch()`. We will discuss each concept in more details next.

docs/en/getters.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Getters
2+
3+
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:
4+
5+
``` js
6+
import Vue from 'vue'
7+
import Vuex from '../../../src'
8+
import actions from './actions'
9+
import mutations from './mutations'
10+
import getters from './getters'
11+
12+
Vue.use(Vuex)
13+
14+
export default new Vuex.Store({
15+
state: { /*...*/ },
16+
actions,
17+
mutations,
18+
getters
19+
})
20+
```
21+
22+
``` js
23+
// getters.js
24+
export function filteredTodos (state) {
25+
return state.messages.filter(message => {
26+
return message.threadID === state.currentThreadID
27+
})
28+
}
29+
```
30+
31+
``` js
32+
// in a component...
33+
import { getters } from './store'
34+
const { filteredTodos } = getters
35+
36+
export default {
37+
computed: {
38+
filteredTodos
39+
}
40+
}
41+
42+
For an actual example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
43+
For an actual example with hot reload API, check out the [Counter Hot Example](https://github.com/vuejs/vuex/tree/master/examples/counter-hot).
44+
45+
46+
This is very similar to [Getters in NuclearJS](https://optimizely.github.io/nuclear-js/docs/04-getters.html).

docs/en/structure.md

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,28 +106,9 @@ For an actual example, check out the [Shopping Cart Example](https://github.com/
106106

107107
### Extracting Shared Computed Getters
108108

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:
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:
110110

111-
``` js
112-
// getters.js
113-
import store from './store'
114-
115-
export function filteredTodos () {
116-
return store.state.messages.filter(message => {
117-
return message.threadID === store.state.currentThreadID
118-
})
119-
}
120-
```
121-
122-
``` js
123-
// in a component...
124-
import { filteredTodos } from './getters'
125-
126-
export default {
127-
computed: {
128-
filteredTodos
129-
}
130-
}
131-
```
111+
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).
132113

133-
This is very similar to [Getters in NuclearJS](https://optimizely.github.io/nuclear-js/docs/04-getters.html).
114+
For more information, check out the [Getters documentation](getters.md)

examples/counter-hot/Counter.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
<template>
22
<div>
3-
Clicked: {{ count }} times
3+
Value: {{ count }}
44
<button @click="increment">+</button>
55
<button @click="decrement">-</button>
66
<button @click="incrementIfOdd">Increment if odd</button>
77
<button @click="incrementAsync">Increment async</button>
8+
<div>
9+
<div>Recent History: {{recentHistory}}</div>
10+
</div>
811
</div>
912
</template>
1013

1114
<script>
1215
import store from './store'
13-
1416
export default {
1517
computed: {
1618
count () {
1719
return store.state.count
18-
}
20+
},
21+
recentHistory: store.getters.recentHistory
1922
},
2023
methods: store.actions
24+
2125
}
2226
</script>

examples/counter-hot/store/getters.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default {
2+
recentHistory (state) {
3+
const end = state.history.length
4+
const begin = end - 5 < 0 ? 0 : end - 5
5+
return state.history
6+
.slice(begin, end)
7+
.toString()
8+
.replace(/,/g, ', ')
9+
}
10+
}

examples/counter-hot/store/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,31 @@ import Vue from 'vue'
22
import Vuex from '../../../src'
33
import actions from './actions'
44
import mutations from './mutations'
5+
import getters from './getters'
56

67
Vue.use(Vuex)
78

89
const state = {
9-
count: 0
10+
count: 0,
11+
history: []
1012
}
1113

1214
const store = new Vuex.Store({
1315
state,
1416
actions,
15-
mutations
17+
mutations,
18+
getters
1619
})
1720

1821
if (module.hot) {
19-
module.hot.accept(['./actions', './mutations'], () => {
22+
module.hot.accept(['./actions', './mutations', './getters'], () => {
2023
const newActions = require('./actions').default
2124
const newMutations = require('./mutations').default
25+
const newGetters = require('./getters').default
2226
store.hotUpdate({
2327
actions: newActions,
24-
mutations: newMutations
28+
mutations: newMutations,
29+
getters: newGetters
2530
})
2631
})
2732
}

examples/counter-hot/store/mutations.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { INCREMENT, DECREMENT } from './mutation-types'
33
export default {
44
[INCREMENT] (state) {
55
state.count++
6+
state.history.push('increment')
67
},
78
[DECREMENT] (state) {
89
state.count--
10+
state.history.push('decrement')
911
}
1012
}

examples/shopping-cart/components/Cart.vue

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,7 @@ const { checkout } = store.actions
1919
2020
export default {
2121
computed: {
22-
products () {
23-
return store.state.cart.added.map(({ id, quantity }) => {
24-
const product = store.state.products.find(p => p.id === id)
25-
return {
26-
title: product.title,
27-
price: product.price,
28-
quantity
29-
}
30-
})
31-
},
22+
products: store.getters.cartProducts,
3223
checkoutStatus () {
3324
return store.state.cart.lastCheckout
3425
},

0 commit comments

Comments
 (0)