javascript - VueJS sever-side-rendering: 计算的属性在商店里看不到变化。
我试图让VueJS中的服务器端渲染工作。
我一直在遵循官方文档,我试图用axios让这个例子工作。端点是正确的,数据确实显示在了 mutation
.
https:/ssr.vuejs.orgguidedata.html。
我也找到了这个页面,并尝试了大部分的例子,其中包括使用getters,vuex mapState,mapGetter等。
这里是 store/index.js
:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import { fetchPage } from './api'
export function createStore () {
return new Vuex.Store({
strict: true,
state: () => ({
res: {}
}),
actions: {
actXY ({ commit }, page) {
fetchPage('homepage').then((item) => {
commit('mutXY', { page, item });
}).catch(error => {
throw new Error(`Store ${error}`);
})
}
},
mutations: {
mutXY (state, { page, item }) {
Vue.set(state.res, page, item);
console.log(state.res.homepage.data)
}
},
getters: {
getXY (state) {
return state.res
}
}
})
}
控制台日志显示了正确的信息,所以这意味着axios端点正在工作并更新状态对象。原本,我是试图调用 mutation
但我后来试着打电话给 getter
. 遗憾的是,新的数据没有被更新到。getter
所以,当然,组件中不会出现任何新的内容。
这就是 HomePage.vue
:
<template>
<div v-if="htmlData">{{ JSON.stringify(htmlData) }}</div>
<div v-else>loading?</div>
</template>
<script>
export default ({
name: 'homepage',
computed: {
htmlData () {
console.log("computed = " + JSON.stringify(this.$store.state.res));
console.log(this.$store.getters.getXY);
return this.$store.getters
// return this.getQuery()
}
},
serverPrefetch () {
return this.getData()
},
mounted () {
console.log("in mounted")
if (!this.item) {
this.getData()
}
},
methods: {
getData () {
return this.$store.dispatch('actXY', 'homepage')
}
}
})
</script>
按书面规定。htmlData
会显示。
{"getXY":{}}
是的,我确实尝试了很多其他的变化 关于如何退回商店里的物品,我想说: getter,
但是什么都没有用。
除了上面链接中的东西,我还找了一下配置文件的变化,我尝试在配置文件中添加了 async
到storeactions、getData()等。
我还尝试在组件中直接进行axios调用,一直没有成功。
由于这是一个已经在VueJS中或多或少完成的项目,我正在将其转换为SSR,我删除了package.json中的所有内容,并重新安装了每一个包,希望可能是旧的vue包中的某个包导致了冲突。
我还尝试了官方文档中的商店代码拆分,并尝试了路由的写法变化。根本没有任何效果。
我想我应该添加打印语句在我运行当前代码时的显示。
computed = undefined
computed mm = undefined
getter = {}
computed get = {"getXY":{}}
{
title: 'Home'...}
组件中的计算属性运行 之前 的突变被设置。这将导致在更新突变之前调用getter。同样地,如果我试图调用改变到 res
直接从组件中调用,当商店被调用和渲染时,突变中没有任何东西。
这是我尝试运行的代码的repo。https:/github.comdt1vue-ssr-尝试。
(我想出了答案。我已经更新了我的回帖,并在下面解释了我的解决方案。)
【回答】:
第一个 storeData()
=> storeData(state)
那么 return this.$store.state.items.homepage.data
=> return this.$store.state.items.homepage && return this.$store.state.items.homepage.data
(或用空主页初始化状态项)
Vue.js中没有SSR。开箱即用. 在你的例子中,你可以得到客户端的数据。
试试这个Store的例子。
export default new Vuex.Store({
strict: true,
state: {
res: null
},
getters: {
getXY(state) {
return state.res;
}
},
mutations: {
mutXY(state, payload) {
state.res = payload;
}
},
actions: {
actXY: function(store) {
fetchPage("homepage")
.then(res => {
store.commit("mutXY", res);
})
.catch(error => {
throw new Error(`Store ${error}`);
});
}
}
});
你可以在组件中获取数据,就像这样
computed: {
htmlData() {
return this.$store.getters.getXY;
}
},
created() {
this.getData();
},
methods: {
getData() {
return this.$store.dispatch("actXY", "homepage");
}
}
【回答】:我的问题是,为什么 this.getData()
在挂载时调用?
如果我的理解是正确的,当你调用服务器端渲染时,你试图在vue组件被挂载之前渲染HTML。如果你调用 this.getData()
在创建而不是挂载?
我还会尝试其他的事情。
- 在组件中硬编码htmlData的值,以检查是否会呈现出来
- 如果可以的话,在存储中硬编码htmlData值,并检查组件是否可以获取存储数据并正确渲染。
- 之后也可以,通过组件的 dispatch 从服务器获取 htmlData,看看是否有效。
- 如果(3)行不通,可以尝试将htmlData推送到一个子组件,这个子组件是在你已经准备好htmlData的情况下才创建的,通过道具发送htmlData到子组件。
好吧,我终于想明白了。
我遇到的主要问题是订单外的调用。当我解决了订购问题后,我遇到了 Converting circular structure to JSON
错误。接下来是想了解VueJS、Vuex商店和axios之间的回调是如何运作的。
最后我想出的解决方案是。
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import * as util from 'util'
Vue.use(Vuex)
import { fetchPage } from './api'
export function createStore () {
return new Vuex.Store({
strict: true,
state: () => ({
res: {}
}),
actions: {
actXY ({ commit }, page) {
return fetchPage(page).then(item => {
commit('mutXY', { page , item } );
})
}
},
mutations: {
mutXY (state, {page, item }) {
Vue.set(state.res, page, item);
}
}
})
}
在调用axios的时候,我必须确保只返回到 response.data
而不是整个响应。在此之前,我得到的是 unhandled promise
错误。
api.js
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios);
Vue.axios.defaults.baseURL = '<url goes here>';
export function fetchPage(page){
return Vue.axios.get(page).then((resp => resp.data))
}
最后但并非最不重要的是,这是 Homepage.vue
.
为了启动更新,我不得不让getData()成为异步的。
<template>
<div v-if="htmlData">
<div>{{ htmlData.title }}</div>
<div>{{ htmlData.description }}</div>
<div>{{ htmlData.html }}</div>
</div>
</template>
<script>
export default ({
name: 'homepage',
computed: {
htmlData () {
return this.$store.state.res.homepage
}
},
serverPrefetch () {
return this.getData()
},
mounted () {
if (!this.item) {
this.getData()
}
},
methods: {
async getData () {
await this.$store.dispatch('actXY', 'homepage')
}
}
})
</script>
希望这能帮助那些遇到这些问题的人.