React 中 lazy, Suspense 以及错误边界(Error Boundaries)的使用

React 中 lazy, Suspense 以及错误边界(Error Boundaries)的使用

lazy

lazyreact 提供的组件懒加载的能力,在官方没有支持 lazy以前,在 react 中咱们通常使用 react-loadable 来实现组件懒加载的能力,可是,lazy 并不支持 服务端渲染(SSR),因此在使用ssr的状况下,lazy 暂时不能使用javascript

React.lazy 接受一个函数,这个函数内部调用 import() 动态导入。它必须返回一个 Promise,该 Promise 须要 resolve 一个 defalut exportReact 组件。html

具体如何使用呢,看下面例子java

import React, { lazy } from 'react'

  const AppTitle = lazy(() => import('./title'))

  class App extends React.Component {
    render () {
      return (
       <AppTitle></AppTitle>
      )
    }
  }

  export default App

复制代码

当咱们把这段代码运行起来的时候,却发现程序报错了react

Error: A React component suspended while rendering, but no fallback UI was specified.

  Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.
      in Unknown (at lazy/index.jsx:8)
      in App (at src/index.js:7)
复制代码

这个时候就须要 react 中内置的组件 Suspense 来配合使用,只须要将 Suspense 引入,而后将异步导入的组件包裹起来,同时也要指定 fallback 属性, 能够支持传入一段 jsx, 或者一个组件实例,相似 <Loading></Loading>webpack

import React, { lazy, Suspense } from 'react'

const AppTitle = lazy(() => import('./title.jsx'))

class App extends React.Component {
    render () {
      return (
        <Suspense fallback={<div>Loading</div>}> <AppTitle></AppTitle> </Suspense>
      )
    }
}

export default App
复制代码

当咱们使用 lazy 以后,咱们能够打开 chromenetwork 而后选择 js 来观察 发起的请求,咱们发现这个时候会出现 1.chunk.js 这种 数字开头的js文件,其实每一个 .js 就对应咱们每个组件,当咱们须要去 指定每一个 异步组件 打包的js文件名时,咱们只须要在 import() 函数中 添加 /* webpackChunkName: "title" */ 这段注释,webpack 在打包时,自动会将咱们指定的名字做为文件名git

import React, { lazy, Suspense } from 'react'

const AppTitle = lazy(
    () => import(/* webpackChunkName: "title" */'./title.jsx')
)

class App extends React.Component {
    render () {
      return (
        <Suspense fallback={<div>Loading</div>}> <AppTitle></AppTitle> </Suspense>
      )
    }
}
export default App

复制代码

若是当一个组件异步加载下载js文件时,网络错误,没法下载 js 文件,那么 react 会表现出什么状况呢github

Error: Loading chunk 3 failed.
  (error: http://192.168.4.183:3000/static/js/title.chunk.js)
复制代码

很明显,Suspense 没法处理这种错误状况, 在 react 中有一个 错误边界 (Error Boundaries)的概念,用来解决这种问题,它是利用了 react 生命周期的 componetDidCatch 方法来处理web

有两种方式,一种是 生命周期 componentDidCatch 来处理错误,还有一种 是 静态方法 static getDerivedStateFromError 来处理错误,chrome

官网的建议是性能优化

请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

import React, { lazy, Suspense } from 'react'

const AppTitle = lazy(
    () => import(/* webpackChunkName: "title" */'./title.jsx')
)

class App extends React.Component {
    state = {
      isError: false
    }
    
    static getDerivedStateFromError(error) {
      return { isError: true };
    }
    
    componentDidCatch (err, info) {
      console.log(err, info)
    }
    
    render () {
      if (this.state.isError) {
        return (<div>error</div>)
      }
      return (
        <div> <Suspense fallback={<div>Loading</div>}> <AppTitle></AppTitle> </Suspense> </div>
      )
    }
}


export default App
复制代码

注意:使用 create-react-app 建立的项目,在开发环境,就算使用了 componentDidCatch 或者 getDerivedStateFromError,错误依然会被抛出,在 build 后,错误将会捕获,不会致使整个项目卸载

根据官方文档所说,在 react 16 之后,任何未被错误边界捕获的错误将会致使整个 React 组件树被卸载。 因此咱们在开发项目时,须要去捕获错误边界的错误,并提供一个备用UI

参考:

  1. 官方文档-错误边界

代码地址

  1. GitHub

react 其余文档

  1. React 中 Context 的使用)的使用
  2. React 中性能优化、 memo、 PureComponent、shouldComponentUpdate 的使用

若是对你有帮助,点个赞吧

相关文章
相关标签/搜索