javascript - 带有 vuex 和 axios 的 Vue.js - 只能在第二次加载时获取数据
问题描述
我创建了一个 Vue.js 应用程序,其中包含一个带有 vuex 的中央存储和一些使用 axios 的基本 API 调用来将数据提取到存储中。
我创建了以下商店操作:
loadConstituencyByAreaCodeAndParliament({commit}, {parliament_id, area_code}) {
axios.get('/cc-api/area-code/' + parliament_id + '/' + area_code)
.then((response) => {
commit('SET_CONSTITUENCY', response.data);
})
.catch(function(error){
commit('SET_CONSTITUENCY', null);
}
)
}
在单个组件文件中,我定义了用户输入区号的表单。然后,此表单调用此操作以获取符合区号的选区:
export default {
name: 'AreaCodeForm',
components: {
PostalCodeInput
},
props: ['parliament_id'],
data: () => ({
postalCode: ''
}),
methods: {
search_area_code(submitEvent) {
let area_code = submitEvent.target.elements.area_code.value;
let payload = {
parliament_id: this.parliament_id,
area_code
}
this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload).
then(() => {
let constituency = this.$store.getters.getConstituency();
// do some things with the data received from the API
// but everything depending on constituency does not work the first time.
// Data received from the API is here available only from the second time on
// wehen this code run.
})
}
}
}
我发现该$store.dispatch
方法返回了一个承诺,但constituency
变量仍然没有接收到通过loadConstituencyByAreaCodeAndParliament
操作获取的数据,但仍然为空。我认为当我使用该promise.then
方法时,数据应该已经存储在商店中,但事实并非如此。当我第二次输入区号时,一切正常。
解决方案
return
处理异步任务时,请始终记住该语句。您有两个选项来重构您的代码,保留promise
或async/await
.
选项1:async/await
async loadConstituencyByAreaCodeAndParliament({ commit }, { parliament_id, area_code }) {
try {
const { data } = await axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
commit('SET_CONSTITUENCY', data)
return data
} catch (error) {
commit('SET_CONSTITUENCY', null)
return error
}
}
备注:
return
的两个块中的语句try/catch
。.get
在 axios 中是可选的,因为默认是get
方法。- 您可以
{ data }
在默认情况下将对象解构赋值与 axios 一起使用。如果我没记错的话,默认的良好 http 响应会检索数据。甚至更复杂的方法可能是const { data: constituencyResponse } = await...
您使用 constituencyResponse 并且每次可能节省 2 或 3 行代码。
选项 2:Promise
第一条路径:在商店里制作所有东西。
// actions
loadConstituencyByAreaCodeAndParliament({ commit, dispatch }, { parliament_id, area_code }) {
axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
.then(({data}) => {
commit('SET_CONSTITUENCY', data)
dispatch('actionTwo', constituency)
})
.catch((error) => {
console.log("error", error)
commit('SET_CONSTITUENCY', null)
})
}
actionTwo({commit}, constituency) {
console.log("actionTwo", constituency)
// do something
commit('COMMIT', 'Final value')
}
// Component
// You handle it with a computed property either referencing a getter or the store state.
{
computed: {
getConstituency(){
return this.$store.state.constituency
},
getSomeOtherConstituency(){
return this.$store.state.constituency.something / 3
}
},
// Optionally if you want to listen and react to changes use a `watcher`.
watch: {
// Gets excecuted each time getConstituency updates.
// ! Must have the same name.
getConstituency(update) {
// Do something, `update` is the new value.
}
}
}
第二条路径:处理组件内部的数据,然后更新存储。
Vue 组件。
methods: {
search_area_code(submitEvent) {
const parliament_id = this.parliament_id
const area_code = submitEvent.target.elements.area_code.value
axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
.then(({data: constituency}) => {
this.$store.commit('SET_CONSTITUENCY', constituency)
// Do whatever you want with constituency now inside the component.
})
.catch((error) => {
console.log("error", error)
this.$store.commit('SET_CONSTITUENCY', null)
})
}
},
笔记:
$store.dispatch 方法返回一个承诺,但选区变量仍然没有接收到使用 loadConstituencyByAreaCodeAndParliament 操作获取的数据,但仍然为空。 当我第二次输入区号时,一切正常。
我认为这里的问题是您要么处理了错误的异步代码,要么尝试实现自定义模式来解决。
正如我之前所说,将 store getter 放在计算属性中,请查看Vuex-docs中的这个示例。
代码洞察:
// Your action doesn't return anything, you must `return axios.get` inside it.
this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload).then(() => {
let constituency = this.$store.getters.getConstituency()
})
// without the `return` statement the code above can be translated to
this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload)
let constituency = this.$store.getters.getConstituency()
// If you opt for async a valid way would be
async doSomething(){
await this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload)
let constituency = this.$store.getters.getConstituency()
}
// IF it still doesnt update anything try `$nextTick` https://vuejs.org/v2/api/
this.$nextTick(() => {
this.data = this.$store.getters.getConstituency()
})
我希望其中的一些内容有所帮助。
推荐阅读
- python - 从布尔数组中一个随机选择的真实元素中获取索引
- javascript - 功能反应本机:将api数据传递给组件时出现错误:PayloadTooLargeError: request entity too large
- python - ErlangC 函数应用程序错误 - TypeError: 'numpy.float64' object is not iterable
- sql-server - 获取架构名称的系统表
- html - CSS 覆盖重要样式 - WordPress BETheme
- mysql - 显示行数 > 0 的表状态
- pagination - odata 和 fetchxml 的区别
- node.js - 具有范围的 NodeJS 请求不适用于 HTML5 视频
- tailwind-css - Tailwind - 覆盖默认过渡持续时间
- ruby - 使用 YAML 序列化和反序列化自定义 Ruby 类