專案地址:react-ssr-demo
服務端渲染一般在活動頁或者官網專案有用到,有利於SEO和首屏渲染優化。
專案用到React-Loadable
實現非同步載入,在服務端渲染時需要對非同步載入的元件進行處理實現同步讀取資料。
附上非同步元件程式碼
class List extends Component {
constructor(props) {
super(props)
}
static fetchData = async (props, params = {}) => {
await props.dispatch(getArticleList(params))
}
componentDidMount() {
if (!this.props.result) {
const { params = {} } = this.props.match || {}
this.constructor.fetchData(this.props, params)
}
}
render() {
const { result = [] } = this.props
return (
<div className="article-page">
{
result.map(({ id, createTime, title }) => (
<div key={id}>{title}---{createTime}</div>
))
}
<Button type="primary">測試</Button>
</div>
)
}
}
複製程式碼
因為服務端是沒有componentDidMount
方法的,所以新增靜態方法fetchData
獲取介面資料,當服務端渲染時,匹配到當前路由元件後則呼叫fetchData
方法,將資料寫入redux
。在單頁渲染時則直接從componentDidMount
獲取即可。
服務端渲染核心程式碼
export default async (req, res, next) => {
//fetch data before component render
const matchedComponents = matchRoutes(routes, req.url).map(({ route }) => {
if (!route.component.preload) { // 同步元件
return route.component;
} else { // 非同步元件
return route.component.preload().then(res => res.default)
}
})
const loadedComponents = await Promise.all(matchedComponents);
const promises = loadedComponents.map(component => {
return component.fetchData ? (component.fetchData(store, req.params || {})) : Promise.resolve(null)
})
await Promise.all(promises).catch(err => console.log('err:---', err))
//匹配路由
if (getMatch(routes, req.url)) {
const context = await renderHtml(req, store)
res.send(context)
} else {
await next()
}
}
複製程式碼
非同步元件主要是通過React-Loadable
的preload
方法獲取元件,然後用Promise.all
統一獲取資料填充到html
即可