# 正文
react ssr 到现在已经不是新技术,技术原理也不复杂,但是真要自己弄出一个完整的轮子并非易事,有非常多的细节和边边角角需要处理。
所以除了自己来造轮子,我们还可以站在巨人的肩膀上,直接使用业内现成的框架进行开发。
造轮子可以,但是不要闭门造车,所以本节我们来了解下业内框架他们是怎样实现的,也侧面的看下我们已有功能的实现是否合理,是为了验证我们的方案,更是学习。
这里主要来看下next.js和egg-react-ssr的实现。
当然还有umi,不过umi ssr代码核心部分也是egg-react-ssr团队贡献的代码,所以就不做对比了。
另外在客户端组件渲染时会使用服务端直出的数据问题,也是参考egg-react-ssr来实现的,只是细节不同。
# 数据预取
看下这两个框架在服务端如何获取组件数据的。
next.js数据预取代码
import React from 'react'
export default class extends React.Component {
static async getInitialProps({ req }) {
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
return { userAgent }
}
render() {
return (
<div>
Hello World {this.props.userAgent}
</div>
)
}
}
当页面渲染时加载数据,使用了一个异步方法getInitialProps。它能异步获取数据,并绑定在props上。当服务渲染时,getInitialProps将会把数据序列化,就像JSON.stringify。
当第一次进入页面时,getInitialProps只会在服务端执行。只有当路由跳转(Link组件跳转或 API 方法跳转)时,客户端才会执行getInitialProps。
另外此方法只能用于页面组件内,不能在子组件内使用。
egg-react-ssr数据预取代码
import React from 'react'
import { Link } from 'react-router-dom'
import './index.less'
function Page (props) {
return (
<div className='normal'>
<div className='welcome' />
<ul className='list'>
{
props.news && props.news.map(item => (
<li key={item.id}>
<div>文章标题: {item.title}</div>
<div className='toDetail'><Link to={`/news/${item.id}`}>点击查看详情</Link></div>
</li>
))
}
</ul>
</div>
)
}
Page.getInitialProps = async (ctx) => {
// ssr渲染模式只在服务端通过Node获取数据,csr渲染模式只在客户端通过http请求获取数据,getInitialProps方法在整个页面生命周期只会执行一次
return __isBrowser__ ? (await window.fetch('/api/getIndexData')).json() : ctx.service.api.index()
}
export default Page
页面初始化时,服务端根据当前请求的path,来确定我们要渲染哪一个组件,getComponent可以理解为一个根据path从路由表中找到匹配的组件的方法,检测该组件上有没有getInitialProps静态方法,这里之所以要用静态方法,是为了不需要实例化就可以拿到方法。
如果有的话,将调用这个方法,将数据作为组件的props传入,使得组件可以通过props.xxx的方式来读取到服务端获取的数据。
# 本应用的数据预取
import React from 'react';
import {
Link
} from 'react-router-dom';
import './index.scss';
import img from '../../public/img.jpg';
import PageContainer from '../../common/components/page-container';
function Index(props) {
return <div className="page-index-box">
<p>首页</p>
<img src={img} />
</div>
}
Index.getInitialProps= async ()=>{
console.log('fetch data index');
//模拟数据请求方法
//...
return {
page: {
tdk: {
title: '首页 - koa-react-ssr',
keywords: '关键词 - koa-react-ssr',
description: '描述'
}
}
};
}
export default PageContainer(Index);
