サーバー側のレンダリングをVueJSで機能させようとしています。
私は公式ドキュメントに従っていて、この例をaxiosを使用して動作させるようにしています。エンドポイントは正しく、データはmutation
に表示されます。
https://ssr.vuejs.org/guide/data.html
私もこのページを見つけて、getter、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,
でストアアイテムを返す方法について他の多くのバリエーションを試しましたが、何も機能しません。
上記のリンクにあるものの他に、設定ファイルのバリエーションを探して、store/actions、getData()などにasync
を追加しようとしました。
また、コンポーネントで直接axiosを呼び出そうとしましたが、成功しませんでした。
これはVueJSでほぼ完成したプロジェクトであり、SSRに変換しています。古いvueパッケージが競合を引き起こしていました。
また、公式ドキュメントから店舗コードを分割し、ルートの記述方法のバリエーションを試しました。何も動作しません。
現在のコードを実行するときに、printステートメントが示す内容を追加する必要があると思います。
computed = undefined
computed mm = undefined
getter = {}
computed get = {"getXY":{}}
{
title: 'Home'...}
コンポーネントの計算されたプロパティは、変異が設定される前に実行されますbefore。これにより、ミューテーションが更新される前にゲッターが呼び出されます。同様に、res
への変更をコンポーネントから直接呼び出そうとしている場合、ストアが呼び出されてレンダリングされているときの変更には何もありません。
これは私が実行しようとしているコードのリポジトリです: https://github.com/dt1/vue-ssr-attempt
(私は答えを見つけました。私は私のために働いているものでリポジトリを更新しました、そして私の解決策の説明は以下です)
さて、私は最終的にこれを理解しました。
私が遭遇した主な問題は、順不同の呼び出しでした。順序を修正すると、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>
うまくいけば、これがこれらの問題のすべてに遭遇している人を助けるでしょう。
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()
を呼び出すと動作しますか?マウントする代わりに作成しましたか?
私が試す他のこと: