React学习笔记——懒加载

340 阅读2分钟

动态加载

Suspense 配合 React.lazy 可以实现动态加载功能

// React.lazy 接受一个函数,这个函数需要动态调用 `import()`。
// 它必须返回一个 Promise ,该 Promise 需要 resolve 一个 default export 的 React 组件。
const ChannelHome = React.lazy(
  () => import(/* webpackChunkName: 'ChannelHome'*/ "./ChannelHome")
);
const ChannelList = React.lazy(
  () => import(/* webpackChunkName: 'ChannelList'*/ "./ChannelList")
);

function Routes() {
  return (
    <Router>
        <React.Suspense fallback={<div>loading...</div>}>
          <Switch>
            <Route path="/index" component={ChannelHome} />
            <Route path="/list" component={ChannelList} />
            <Redirect from={"/*"} to={"/index"} />
          </Switch>
        </React.Suspense>
    </Router>
  );
}

Suspense 原理

Suspense 在执行内部可以通过 try{}catch{} 方式捕获异常,这个异常通常是一个 Promise ,可以在这个 Promise 中进行数据请求工作,Suspense 内部会处理这个 Promise ,Promise 结束后,Suspense 会再一次重新 render 把数据渲染出来,达到异步渲染的效果。

image.png

渲染错误边界

为了避免某一组件渲染出错导致页面白屏,React提供componentDidCatch 和 static getDerivedStateFromError() 两个额外的生命周期,去挽救由于渲染阶段出现问题造成 UI 界面无法显示的情况。

componentDidCatch

componentDidCatch 可以捕获异常,它接受两个参数:

  • 1 error —— 抛出的错误。
  • 2 info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。

componentDidCatch 作用:

  • 可以调用 setState 促使组件渲染,并做一些错误拦截功能。
  • 监控组件,发生错误,上报错误日志。

static getDerivedStateFromError

getDerivedStateFromError 返回的值可以合并到 state,作为渲染使用。由于是静态方法,所以不能使用setState。
注意事项: 如果存在 getDerivedStateFromError 生命周期钩子,那么将不需要 componentDidCatch 生命周期再降级 ui。
官方推荐使用getDerivedStateFromError这个方法。

具体实例如下:


<ErrorBoundary>
  <Home />
</ErrorBoundary>

// ErrorBoundary
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染能够显示降级后的 UI
    console.log('---错误边界捕获到错误---', error)
    return { hasError: true }
  }

  componentDidCatch(error, errorInfo) {
    // 你同样可以将错误日志上报给服务器
    console.log('---错误边界捕获到错误---', error, errorInfo)
  }

  render() {
    if (this.state.hasError) {
      return (
        <div>页面发生异常</div>
      )
    }

    return this.props.children
  }
}

export default ErrorBoundary