vuex存储变量在填充来自API的数据存储之前使用



我试图通过vuex从API获取数据。

这是一个存储中的操作函数:

async getEpisodeFromApi({ commit }, id) {
const data = {
id
};
return await axios.get(Api.getUrl(data)).then((response) => {
console.log("response.dat0dfgsdfa", response.data);
commit("setEpisode", response.data);
});
}
这是一个Api类(它返回链接字符串):
class Api {
getUrl(data) {
return "https://www.breakingbadapi.com/api/episodes/" + data.id;
}
}
export default new Api();

这就是我尝试与数据交互的方式。

async beforeCreate() {
await this.$store.dispatch(
"getEpisodeFromApi",
this.$route.params.episode_id
);
},
async mounted() {
const episode = this.$store.state.episode;
episode.characters.forEach((name) => {
this.charactersInEpisode.push(
this.$store.characters.find((character) => character.name === name)[0]
);
});
}

但是store填充状态比挂载的钩子开始工作要慢。我总是得到episode作为空变量episode.characters是未定义的

episode.characters未定义

我如何在存储中填充状态,并从存储中获得比挂载钩子运行代码更快的数据?

您可以尝试将beforeCreated钩子转换为方法

methods: {
async getData() {
await this.$store.dispatch(
"getEpisodeFromApi",
this.$route.params.episode_id
);
},
}

then in mounted hook await for data:

async mounted() {
await this.getData()
const episode = this.$store.state.episode;
episode.characters.forEach((name) => {
this.charactersInEpisode.push(
this.$store.characters.find((character) => character.name === name)[0]
);
});
}

这可能是一个计算属性。当状态被来自API的数据填充时,它将被更新:

computed: {
charactersInEpisode(){
const episode = this.$store.state.episode;
if (!episode) return []
return episode.characters.map((name) => {
return this.$store.state.characters.find((character) => character.name === name)[0]
});
}
}

<!DOCTYPE html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
rel="stylesheet"
/>
<link href="https://cdn.jsdelivr.net/npm/vuetify@1.x/dist/vuetify.min.css" rel="stylesheet" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"
/>
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-container>
<h2 class="red pa-2 primary white--text">Only Limited resolved questions</h2>
<section v-for="(item, index) in questions" :key="index">
<li>{{index}}.- {{item }}</li>
</section>
<section>
<h3>Response question 1</h3>
<blockquote class="pa-3 secondary white--text">
This can be done from any lifecycle hook, or a method. For the example, beforeCreate is used.
</blockquote>
<pre>
{{ $store.state.episode }}
</pre>
</section>
<section>
<h3>Response question 2</h3>
<blockquote class="pa-3 secondary white--text">This via getter and computed property</blockquote>
<div v-for="(item, i) in charactersInEpisode" :key="i">{{ item }}</div>
</section>
</v-container>
</v-content>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@2.0.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@1.x/dist/vuetify.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// STORE (e.g. store/index.js)
const storeTest = new Vuex.Store({
state: {
episode: null,
},
mutations: {
setEpisode(state, payload) {
state.episode = payload[0]; // POSSIBLE IMPROVE FROM BACKEND, SENDING OBJECT {} (NOW ARRAY [])
},
},
actions: {
async getEpisodeFromApi({ commit }, id) {
const data = {
id,
};
return await axios.get(`https://www.breakingbadapi.com/api/episodes/${data.id}`).then((response) => {
console.log("response.dat0dfgsdfa", response.data);
commit("setEpisode", response.data);
});
},
},
getters: {
charactersInEpisode: (state) => {
console.log("EXE GETTER", state);
if (state.episode) {
return state.episode.characters;
} else {
return [];
}
},
},
});
// DATA LOCAL
const modelCompartido = {
questions: {
1: "How can I fill state in store?",
2: "get the data from store faster than mounted hook runs code?",
},
};
new Vue({
el: "#app",
data: modelCompartido,
store: storeTest,
mounted() {},
async beforeCreate() {
const episode_id = 1; // TODO: use ID for simplex example, next use/replace the params: this.$route.params.episode_id
await this.$store.dispatch("getEpisodeFromApi", episode_id);
},
computed: {
...Vuex.mapGetters(["charactersInEpisode"]),
},
});
</script>
</body>
</html>

我限制自己只解决问题(已解决的问题),并且由于问题中未提供的未定义变量导致的错误,我消除了其余的代码。

回答问题1:如何在存储中填充状态?

这可以从任何生命周期钩子或方法中完成。例如,使用beforeccreate

async beforeCreate() {
const episode_id = 1; // TODO: use ID for simplex example, next use/replace the params: this.$route.params.episode_id
await this.$store.dispatch("getEpisodeFromApi", episode_id);
},

回答问题2:从存储中获取数据比挂载的钩子运行代码更快?

这可以使用next (Vue框架)通过asyncData在渲染前发出请求,但如果您只使用Vue,则可以通过getter和computed property来控制它。(除其他方式外);最后一个是我提出的解决方案(运行代码)。

// store/index.js
getters: {
charactersInEpisode: (state) => {
console.log("EXE GETTER", state);
if (state.episode) {
return state.episode.characters;
} else {
return [];
}
},
},
// Component.vue
computed: {
...Vuex.mapGetters(["charactersInEpisode"]),
},

注意:

setEpisode(state, payload) {
state.episode = payload[0]; // POSSIBLE IMPROVE FROM BACKEND, SENDING OBJECT {} (NOW ARRAY [])
},

您可以运行解决方案并检查反应性。我希望这将是有用的

最新更新