下面谈几个重点。
我们知道,在常规的 Vue 前端渲染中,组件请求 Ajax 一般是这么写的:“在 mounted 中调用 this.fetchData,然后在回调里面把返回数据写到实例的 data 中,这就 ok 了。”
在 SSR 中,这是不行的,因为服务器并不会执行 mounted 周期。那么我们是否可以把 this.fetchData
提前到 created 或者 beforeCreate 这两个生命周期中执行?同样不行。原因是:this.fetchData 是异步请求,请求发出去之后,没等数据返回呢,后端就已经渲染完了,无法把 Ajax 返回的数据也一并渲染出来。
所以,我们得提前知道都有哪些组件有 Ajax 请求,等把这些 Ajax 请求都返回了数据之后,才开始组件的渲染。
// store.js
function fetchBar() {
return new Promise(function (resolve, reject) {
resolve('bar ajax 返回数据');
});
}
export default function createStore() {
return new Vuex.Store({
state: {
bar: '',
},
actions: {
fetchBar({commit}) {
return fetchBar().then(msg => {
commit('setBar', {msg})
})
}
},
mutations:{
setBar(state, {msg}) {
Vue.set(state, 'bar', msg);
}
}
})
}
// Bar.uve
asyncData({store}) {
return store.dispatch('fetchBar');
},
computed: {
bar() {
return this.$store.state.bar;
}
}
组件的 asyncData 方法已经定义好了,但是怎么索引到这个 asyncData 方法呢?先看我的根组件 App.vue 是怎么写的。
// App.vue
<template>
<div>
<h1>App.vue</h1>
<p>vue with vue </p>
<hr>
<foo1 ref="foo_ref"></foo1>
<bar1 ref="bar_ref"></bar1>
<bar2 ref="bar_ref2"></bar2>
</div>
</template>
<script>
import Foo from './components/Foo.vue';
import Bar from './components/Bar.vue';
export default {
components: {
foo1: Foo,
bar1: Bar,
bar2: Bar
}
}
</script>
从根组件 App.vue 我们可以看到,只需要解析其 components 字段,便能依次找到各个组件的 asyncData 方法了。
// entry-server.js
export default function (context) {
// context 是 vue-server-render 注入的参数
const store = createStore();
let app = new Vue({
store,
render: h => h(App)
});
// 找到所有 asyncData 方法
let components = App.components;
let prefetchFns = [];
for (let key in components) {
if (!components.hasOwnProperty(key)) continue;
let component = components[key];
if(component.asyncData) {
prefetchFns.push(component.asyncData({
store
}))
}
}
return Promise.all(prefetchFns).then((res) => {
// 在所有组件的 Ajax 都返回之后,才最终返回 app 进行渲染
context.state = store.state;
// context.state 赋值成什么,window.__INITIAL_STATE__ 就是什么
return app;
});
};
内容版权声明:除非注明,否则皆为本站原创文章。
