下面谈几个重点。
我们知道,在常规的 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; }); };
内容版权声明:除非注明,否则皆为本站原创文章。