状態を変更する非同期アクションをディスパッチした後、vuexでゲッターを呼び出す適切な方法は何ですか?
私は、私が何を意味するのかを説明するためのサンプルスニペットを作成しました。ご覧のとおり、_state.persons
_が空であるため、getLastNameByName()
は失敗します。奇妙なことに、そのゲッターで_state.persons
_を出力すると、API呼び出しの後に配列が出力されます。
予想される動作は、getLastNameByName('John')
が_{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()は待機可能なオブジェクトを返しません。約束を確認してください:
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>
とにかく、ストアへの非同期呼び出しを直接処理することは適切な方法ではありません。この場合、より良い解決策は、watch
状態を保存するか、computed
プロパティを使用することです。
Jsbin.comでいくつかの改善を試み、問題はありませんでした。
<!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>