从 REST API 获取的 Vuex 渲染数据
Posted
技术标签:
【中文标题】从 REST API 获取的 Vuex 渲染数据【英文标题】:Vuex rendering data that is fetched from REST API 【发布时间】:2017-05-27 07:44:58 【问题描述】:对于这样的组件
<template>
<div>
<router-link :to="name:'section', params: sectionId: firstSectionId ">Start</router-link>
</div>
</template>
<script lang="ts">
import mapActions from "vuex"
export default
mounted()
this.getSectionId()
,
computed:
firstSectionId()
return this.$store.state.firstSectionId
,
methods: mapActions(["getSectionId"])
</script>
商店:
const store: any = new Vuex.Store(
state:
firstSectionId: null
,
// actions,
// mutations
)
我在 getSectionId
操作中有一个 Web 请求,它异步获取数据并调用将填充 firstSectionId
到 state
的突变。在初始渲染期间,firstSectionId
是 null
,我收到警告说在渲染router-link
期间缺少必需的参数。
这里添加v-if="firstSectionId"
是没有问题的。但总的来说,从服务器获取数据以显示的方法是什么?目前我所有的组件都在渲染之前检查存储中是否存在数据,这是正常的还是有更好的方法在渲染之前等待数据加载?
【问题讨论】:
要在渲染之前等待数据加载,您使用服务器端渲染。除此之外,为什么要“等待数据”?我们每天都会看到网站和应用程序使用“加载”指示器加载静态页面结构,然后在它们到达时用数据填充它们。显然,尽可能早地向用户展示是最好的体验。 【参考方案1】:异步获取数据的一种方法是在 vuex 存储 actions 中使用 promise。
Vue.http.get(API_URL)
.then((response) =>
//use response object
)
.catch((error) =>
console.log(error.statusText)
);
为了证明我向this route 提出请求。您可以看到响应应该是什么样子。让我们将响应对象保存在 state.users 数组中。
store.js
const store = new Vuex.Store(
state:
users: []
,
mutations:
FETCH_USERS(state, users)
state.users = users
,
actions:
fetchUsers( commit , self )
Vue.http.get("https://jsonplaceholder.typicode.com/users")
.then((response) =>
commit("FETCH_USERS", response.body);
self.filterUsers();
)
.catch((error) =>
console.log(error.statusText)
);
)
export default store
您注意到提交后有self.filteruser()
方法。那是关键时刻。在此之前,我们提交一个突变,这是同步操作,我们确信我们的响应会在 store.state 中,可以在filterUsers()
方法中使用(别忘了传递自我参数)
Users.vue
import store from "../store/store"
export default
name: 'users',
created()
this.$store.dispatch("fetchUsers", self: this )
,
methods:
filterUsers()
//do something with users
console.log("Users--->",this.$store.state.users)
更好的方法(ES6 和 ES7)
用于异步编程的 ES6 Promise
//User.vue
created()
this.$store.dispatch("fetchUser").then(() =>
console.log("This would be printed after dispatch!!")
)
//store.js
actions:
fetchUser( commit )
return new Promise((resolve, reject) =>
Vue.http.get("https://jsonplaceholder.typicode.com/users")
.then((response) =>
commit("FETCH_USERS", response.body);
resolve();
)
.catch((error) =>
console.log(error.statusText);
);
);
ES7:异步/等待
要摆脱回调地狱,并改进异步编程,请使用 async
函数,您可以在 Promise 上使用 await
。代码看起来更容易理解(就像它是同步的一样),但是代码对于浏览器来说是不可读的,所以你需要 Babel transpiler 来运行它。
actions:
async actionA ( commit )
commit('gotData', await getData())
,
async actionB ( dispatch, commit )
await dispatch('actionA') // wait for actionA to finish
commit('gotOtherData', await getOtherData())
【讨论】:
没有什么对我有用。我正在尝试从 WordPress API 获取内容,但页面加载时间约为 40 毫秒,并且在页面加载后发送 API 调用。我正在使用服务器端渲染并希望在页面加载时渲染内容。 Vuex 商店没有帮助 ES6 的方式帮助了我。【参考方案2】:根据我的经验,如果您使用与预期结果相同类型的空值预设状态(当然,如果您知道会发生什么),例如,您可以跳过一些检查。如果您有一组项目,请以 []
而不是 null
开头,因为它不会破坏 v-for
指令、.length
检查和类似的数据访问尝试。
但一般来说,添加v-if
是很正常的事情。有a section about this in the vue-router
documentation,检查属性是否存在正是它所暗示的。它提到的另一种可能的解决方案是在beforeRouteEnter
guard 中获取数据,这可以确保您始终可以使用已经可用的数据访问组件。
最终,两种解决方案都是正确的,它们之间的决定更多的是一个 UX/UI 问题。
【讨论】:
【参考方案3】:我对位置和谷歌地图 api 有类似的要求。我需要从 API 中获取我的位置,将它们加载到列表中,然后在地图组件中使用这些位置来创建标记。我使用 axios 在 Vuex 操作中获取数据,在我的状态下使用突变加载数据,然后使用 getter 在已安装的生命周期挂钩中检索结果数组。这导致在异步操作解析之前触发了一个空数组。
我用 store.subscribe 来解决这个问题:
<template>
<div class="google-map" :id="mapName"></div>
</template>
<script>
import GoogleMapsLoader from 'google-maps';
import mapGetters from 'vuex';
export default
name: 'google-map',
props: ['name'],
computed:
...mapGetters(
locations: 'locations/locations',
),
,
data()
return
mapName: `$this.name-map`,
;
,
mounted()
this.$store.subscribe((mutation, state) =>
if (mutation.type === 'locations/SAVE_LOCATIONS')
GoogleMapsLoader.KEY = 'myKey';
GoogleMapsLoader.load((google) =>
/* eslint-disable no-new */
const map = new google.maps.Map(document.getElementById('locations-map'));
// loop through locations and add markers to map and set map boundaries
const bounds = new google.maps.LatLngBounds();
// I access the resulting locations array via state.module.property
state.locations.locations.forEach((location) =>
new google.maps.Marker(
position:
lat: location.latitude,
lng: location.longitude,
,
map,
);
bounds.extend(
lat: location.latitude,
lng: location.longitude,
);
);
map.fitBounds(bounds);
);
);
,
;
【讨论】:
谢谢你,这真的帮助了我。在初始页面加载时保持空白存储并使用计算值没有帮助。只有 $store.subscribe 工作,我不明白 为什么 但我很感激。你知道为什么它比计算效果更好吗? 这是几年前的事了,现在看,我应该在加载地图之前获取驱动标记的数据。那会干净得多。以上是关于从 REST API 获取的 Vuex 渲染数据的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 rest API 在应用程序启动时正确初始化 Vuex 商店?
Vue.js - 从 API 获取数据并在 Vuex 状态更改时重新加载组件