admin管理员组文章数量:1353114
I'm trying to get server side rendering to work in VueJS.
I've been following the official docs, and I'm attempting to get this example to work using axios. The endpoint is correct and the data does show up in the mutation
.
.html
I also found this page and tried most of these examples, which includes using getters, vuex mapState, mapGetter, etc:
vue.js 2 how to watch store values from vuex
Here is 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 ({ mit }, page) {
fetchPage('homepage').then((item) => {
mit('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
}
}
})
}
the console log is displaying the correct information, so that means the axios endpoint is working and updating the state object. Originally, I was attempting to call the mutation
, but I've since tried calling the getter
. Unfortunately, the new data is not being updated in the getter
, so of course, nothing new shows up in the ponent.
This is HomePage.vue
:
<template>
<div v-if="htmlData">{{ JSON.stringify(htmlData) }}</div>
<div v-else>loading?</div>
</template>
<script>
export default ({
name: 'homepage',
puted: {
htmlData () {
console.log("puted = " + 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>
As written, htmlData
will show:
{"getXY":{}}
Yes, I did attempt many other variations on how to return the store item in the getter,
but nothing is working.
Aside from the stuff in the above links, I've also looked around for variations on config files, I attempted to add async
to store/actions, getData(), etc.
I also attempted to make the axios call directly in the ponent, which has had no success.
Since this is a project that was already more-or-less pleted in VueJS that I'm converting to SSR, I removed everything from package.json and reinstalled every package, in the hopes that maybe one of the old vue packages was causing a conflict.
I also attempted the store code splitting from the official docs, and tried variations on how the routes are written. Nothing at all works.
I think I should add what the print statements show when I run my current code:
puted = undefined
puted mm = undefined
getter = {}
puted get = {"getXY":{}}
{
title: 'Home'...}
The puted property in the ponent runs before the mutation is set. This causes the getter to be called before the mutation is updated. Likewise, if I'm attempting to call changes to res
directly from the ponent, there is nothing in mutations when the store is being called and rendered.
This is a repo of the code I'm attempting to run:
(I figured out the answer. I've updated the repo with what is working for me, and explanation of my solution is below)
I'm trying to get server side rendering to work in VueJS.
I've been following the official docs, and I'm attempting to get this example to work using axios. The endpoint is correct and the data does show up in the mutation
.
https://ssr.vuejs/guide/data.html
I also found this page and tried most of these examples, which includes using getters, vuex mapState, mapGetter, etc:
vue.js 2 how to watch store values from vuex
Here is 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 ({ mit }, page) {
fetchPage('homepage').then((item) => {
mit('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
}
}
})
}
the console log is displaying the correct information, so that means the axios endpoint is working and updating the state object. Originally, I was attempting to call the mutation
, but I've since tried calling the getter
. Unfortunately, the new data is not being updated in the getter
, so of course, nothing new shows up in the ponent.
This is HomePage.vue
:
<template>
<div v-if="htmlData">{{ JSON.stringify(htmlData) }}</div>
<div v-else>loading?</div>
</template>
<script>
export default ({
name: 'homepage',
puted: {
htmlData () {
console.log("puted = " + 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>
As written, htmlData
will show:
{"getXY":{}}
Yes, I did attempt many other variations on how to return the store item in the getter,
but nothing is working.
Aside from the stuff in the above links, I've also looked around for variations on config files, I attempted to add async
to store/actions, getData(), etc.
I also attempted to make the axios call directly in the ponent, which has had no success.
Since this is a project that was already more-or-less pleted in VueJS that I'm converting to SSR, I removed everything from package.json and reinstalled every package, in the hopes that maybe one of the old vue packages was causing a conflict.
I also attempted the store code splitting from the official docs, and tried variations on how the routes are written. Nothing at all works.
I think I should add what the print statements show when I run my current code:
puted = undefined
puted mm = undefined
getter = {}
puted get = {"getXY":{}}
{
title: 'Home'...}
The puted property in the ponent runs before the mutation is set. This causes the getter to be called before the mutation is updated. Likewise, if I'm attempting to call changes to res
directly from the ponent, there is nothing in mutations when the store is being called and rendered.
This is a repo of the code I'm attempting to run: https://github./dt1/vue-ssr-attempt
(I figured out the answer. I've updated the repo with what is working for me, and explanation of my solution is below)
Share Improve this question edited May 26, 2020 at 20:07 dizzystar asked May 16, 2020 at 11:24 dizzystardizzystar 1,08512 silver badges23 bronze badges 3- Why you dont use Nuxt.js ? – Ilijanovic Commented May 16, 2020 at 11:34
- Not sure if it's related - on mounted you call this.fetchItem, but I can't see it's declaration. Am I missing something? – Karin C Commented May 16, 2020 at 11:42
- @KarinC, mounted is never called in server side rendering. I know it's confusing to have the artifact there, but it doesn't cause any issues at this moment. – dizzystar Commented May 16, 2020 at 15:37
4 Answers
Reset to default 2Okay, I finally figured this out.
The main issues I ran into were the out-of-order calls. When I fixed the ordering, I was running into Converting circular structure to JSON
errors. Next was trying to understand how the callbacks function between VueJS, Vuex stores, and axios.
The final solution I came up with is:
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 ({ mit }, page) {
return fetchPage(page).then(item => {
mit('mutXY', { page , item } );
})
}
},
mutations: {
mutXY (state, {page, item }) {
Vue.set(state.res, page, item);
}
}
})
}
Then when making the axios call, I had to be sure to return only the response.data
instead of the entire response. Before this, I getting a unhandled promise
error.
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))
}
Last but not least, this is Homepage.vue
.
In order to fire an update, I had to make getData() asynchronous:
<template>
<div v-if="htmlData">
<div>{{ htmlData.title }}</div>
<div>{{ htmlData.description }}</div>
<div>{{ htmlData.html }}</div>
</div>
</template>
<script>
export default ({
name: 'homepage',
puted: {
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>
Hopefully this helps anyone who's running into all of these issues.
First storeData()
=> storeData(state)
then return this.$store.state.items.homepage.data
=> return this.$store.state.items.homepage && return this.$store.state.items.homepage.data
(or initialize the state items with an empty homepage)
My question is why is the this.getData()
called in mounted?
If I understand the process correctly, when you call server side rendering you are trying to render the HTML before the vue ponent is mounted. Would it work if you called this.getData()
in created instead of mounted?
Other things I would try:
- hardcode htmlData value in ponent to check if it would render
- if that works, hardcode htmlData value in store and check if the ponent can fetch that store data and render properly too
- after that works too, fetch htmlData from server via dispatch from the ponent, see if it works.
- if (3) does not work, try pushing the htmlData to a child ponent that is created only when you already have htmlData ready, send htmlData to the child ponent via props
There is no SSR in Vue.js out of the box. In your example you can get data on client.
Try this example for 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.mit("mutXY", res);
})
.catch(error => {
throw new Error(`Store ${error}`);
});
}
}
});
And you can get data in the ponent as such:
puted: {
htmlData() {
return this.$store.getters.getXY;
}
},
created() {
this.getData();
},
methods: {
getData() {
return this.$store.dispatch("actXY", "homepage");
}
}
本文标签: javascriptVueJS seversiderendering computed property not seeing changes in storeStack Overflow
版权声明:本文标题:javascript - VueJS sever-side-rendering: computed property not seeing changes in store - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743926261a2563015.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论