VueJS 服务器端渲染:计算属性没有看到存储中的变化

diz*_*tar 8 javascript vue.js server-side-rendering vuex

我正在尝试让服务器端渲染在 VueJS 中工作。

我一直在关注官方文档,并且正在尝试使用 axios 使此示例正常工作。端点是正确的,数据确实显示在mutation.

https://ssr.vuejs.org/guide/data.html

我也找到了这个页面并尝试了其中的大部分示例,其中包括使用 getter、vuex mapState、mapGetter 等:

vue.js 2 如何从 vuex 中观察存储值

这是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
            }
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

控制台日志显示正确的信息,这意味着 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>
Run Code Online (Sandbox Code Playgroud)

如所写,htmlData将显示:

{"getXY":{}}
Run Code Online (Sandbox Code Playgroud)

是的,我确实尝试了许多其他关于如何退回商店商品的变体,getter,但没有任何效果。

除了上面链接中的内容,我还四处寻找配置文件的变化,我尝试添加async到 store/actions、getData() 等。

我也尝试过直接在组件中进行 axios 调用,没有成功。

由于这是一个已经或多或少在 VueJS 中完成的项目,我正在将其转换为 SSR,因此我从 package.json 中删除了所有内容并重新安装了每个包,希望可能是旧的 vue 包之一导致了冲突。

我还尝试了从官方文档中拆分商店代码,并尝试了如何编写路由的变体。什么都不起作用。

我想我应该在运行当前代码时添加打印语句显示的内容:

computed = undefined
computed mm  = undefined
getter = {}
computed get  = {"getXY":{}}
{
  title: 'Home'...}
Run Code Online (Sandbox Code Playgroud)

组件中的计算属性在设置突变之前运行。这会导致在更新突变之前调用 getter。同样,如果我尝试res直接从组件调用更改,则在调用和呈现商店时不会发生任何变化。

这是我试图运行的代码的回购:https : //github.com/dt1/vue-ssr-attempt

(我想出了答案。我已经用对我有用的东西更新了 repo,下面是我的解决方案的解释)

diz*_*tar 1

好吧,我终于明白了这一点。

我遇到的主要问题是乱序调用。当我修正顺序时,我遇到了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);
            }
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

然后,在进行 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))
}
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的一点是,这是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>
Run Code Online (Sandbox Code Playgroud)

希望这对遇到所有这些问题的人有所帮助。