服务端渲染 Node 层直接获取数据
在 Egg 项目如果使用模板引擎规范时是通过 render 方法进行模板渲染,render 的第一个参数模板路径,第二个参数时模板渲染数据. 如如下调用方式:
async index(ctx) {// 获取数据,可以是从数据库,后端 Http 接口 等形式const list = ctx.service.article.getArtilceList();// 对模板进行渲染,这里的 index.js 是 React jsx 文件通过 Webpack 构建的 JSBundle 文件await ctx.render('index.js', { list });}
从上面的例子可以看出,这种使用方式是非常典型的也容易理解的模板渲染方式。在实际业务开发时,对于常规的页面渲染也建议使用这种方式获取数据,然后进行页面渲染。Node 获取数据后,在 React 文件里面就可以通过 this.props.list 的方式拿到 Node 获取的数据,然后就可以进行 React 模板 jsx 文件数据绑定了。
在这里有个高阶用法,可以直接把 ctx 等 Node 对象传递到第二个参数里面, 这个时候你在模板里面就直接拿到 ctx 这些对象。 但这个时候就需要自己处理好 SSR 渲染时导致的 hydrate 问题,因为前端hydrate时并没有 ctx 对象。
async index(ctx) {// 获取数据,可以是从数据库,后端 Http 接口 等形式const list = ctx.service.article.getArtilceList();// 对模板进行渲染,这里的 index.js 是 React jsx 文件通过 Webpack 构建的 JSBundle 文件await ctx.render('index.js', { ctx, list });}
如果把 ctx 对象传递到 React JSX 模板文件里面,你可以通过在 React jsx 模板文件进行 ctx.service.article.getArtilceList() 调用, 也就是在前端代码模板里面进行 Node 调用。
服务端渲染 asyncData 方式获取数据
在 React 进行 SSR 时涉及数据的请求方式,除了 Node 层直接获取数据方式可以继续使用,还可以在 React 组件里面编写 asyncData 方式获取数据。具体实现见 egg-view-react-ssr (^3.0.0) 插件 asyncData 逻辑处理。
egg-view-react-ssr 插件会判断 render 的组件是否包含静态的 asyncData 方法 (可以是 async 形式或者返回 Promise 方法),如果包括,则触发 asyncData 逻辑,然后获取的到数据与 Node 端的数据进行合并。
React 组件代码
${root}/app/web/page/test.jsx
'use strict';import React, { Component } from 'react';import request from '../../framework/request';class AsyncDataMode extends Component {static async asyncData(locals) {return request.get(`/test/api/article`, locals);}render() {const { title, article } = this.props;return <div><h1 className="easy-article-detail-title">{title}</h1><h2 className="easy-article-detail-title">{article.title}</h2><div className="easy-article-info"><iframe src={article.url} frameBorder="0" width="100%" style={{minHeight: '800px'}}></iframe></div></div>;}}export default AsyncDataMode;
Node 渲染逻辑
添加
${root}/app/controller/test.jsEgg 路由配置
'use strict';module.exports = app => {return class TestController extends app.Controller {async index(ctx) {const title = 'Frontend asyncData 获取渲染数据';await ctx.render('test.js', { title });}async article(ctx) {const article = await ctx.service.article.query({ id: 1 });ctx.body = { article };}};};
Egg 路由配置
添加
${root}/app/router.jsEgg 路由配置
module.exports = app => {const { router, controller } = app;router.get('/test', controller.test.index);router.get('/test/api/article', controller.test.article);};
Webpack 构建配置
添加
${root}/webpack.config.js新增页面 entry 配置
module.exports = {entry: {test: 'app/web/page/test.jsx',}}
