Quelle est la bonne façon d'appeler un getter in vuex après avoir envoyé une action asynchrone qui a muté l'état?
J'ai créé un exemple d'extrait pour illustrer ce que je veux dire. Comme vous pouvez le voir, getLastNameByName()
échoue car state.persons
Est vide. La chose étrange est que si j'imprime state.persons
Dans cet getter, il imprime le tableau après appel api.
Le comportement attendu est que getLastNameByName('John')
renvoie {name: 'John', lastname: 'Smith'}
const store = new Vuex.Store({
state: {
persons: []
},
getters: {
getLastNameByName: (state) => (name) => {
// console.log(state.persons) returns the state, yet I cannot call .find on it
return state.persons.find(element => {
return element.name === name
}).lastname
},
},
mutations: {
setPersons: (state, payload) => {
state.persons = [...payload]
}
},
actions: {
async getPeople({commit}) {
return new Promise(function(resolve, reject) {
setTimeout(async () => {
commit('setPersons', [{
name: 'John',
lastname: 'Smith'
}, {
name: 'Sarah',
account: 'Appleseed'
}])
resolve();
}, 1000)
})
}
}
})
new Vue({
store,
el: '#app',
mounted() {
this.$store.dispatch('getPeople').then( () => {
console.log(this.$store.getters.getLastNameByName('John'))
})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>
<div id="app">
</div>
setTimeout () ne renvoie pas d'objet attendu. Vérifiez avec promesse:
const store = new Vuex.Store({
state: {
persons: []
},
getters: {
getLastNameByName: (state) => (name) => {
return state.persons.find(element => {
return element.name === name
}).lastname
},
},
mutations: {
setPersons: (state, payload) => {
state.persons = [...payload]
}
},
actions: {
async getPeople({commit}) {
return new Promise(function(resolve, reject) {
setTimeout(async () => {
commit('setPersons', [{
name: 'John',
lastname: 'Smith'
}, {
name: 'Sarah',
account: 'Appleseed'
}])
resolve();
}, 1000)
})
}
}
})
new Vue({
store,
el: '#app',
mounted() {
this.$store.dispatch('getPeople').then(() => {
console.log(this.$store.getters.getLastNameByName('John'));
})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>
<div id="app">
</div>
Quoi qu'il en soit, la gestion directe des appels asynchrones à stocker n'est pas une bonne façon. Je pense que dans ce cas, la meilleure solution consiste à watch
stocker l'état ou utiliser computed
propriétés.
Essayé sur jsbin.com avec quelques améliorations et aucun problème:
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Vue example</title>
<div id="app">
<show-person
:name="getLastName('John')"
></show-person>
</div>
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
persons: []
},
getters: {
getLastName: state => name => {
return state.persons.length
? state.persons.find(element => {
return element.name === name
}).lastname
: ''
}
},
mutations: {
setPersons: (state, payload) => {
state.persons = [...payload]
}
},
actions: {
getPeople: ({ commit }) => new Promise(res => {
const data = [
{name: 'John', lastname: 'Smith'},
{name: 'Sarah', account: 'Appleseed'}
]
setTimeout(() => {
commit('setPersons', data)
res()
}, 1000)
})
}
})
const ShowPerson = {
functional: true,
render: (h, ctx) => h('p', ctx.props.name)
}
new Vue({
store,
el: '#app',
components: {
ShowPerson
},
computed: {
...Vuex.mapGetters([
'getLastName'
])
},
methods: {
...Vuex.mapActions([
'getPeople'
])
},
created () {
this.getPeople()
}
})
</script>