React + React-Loadable 實現服務端渲染

onfuns發表於2019-01-18

專案地址: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-Loadablepreload方法獲取元件,然後用Promise.all統一獲取資料填充到html即可

相關文章