【工作笔记】如何处理react中的渲染异常

2018-10-23  本文已影响0人  张柳哥

我们知道,在使用 react 渲染页面的时候,如果某个子组件发生了错误,将会造成整个页面的白屏:

// page 组件,代表整个页面
class page extends React.Component {
  // 如果 Component1 渲染失败,将会导致整个 page 组件渲染失败
  render() {
    return (
      <div>
        <Component1></Component1>
        <Component2></Component2>
        <Component3></Component3>
      </div>
    )
  }
}

这样就会造成一个问题,有些子组件并没有那么重要,是否能够渲染出来,都不应该影响到整个页面。

为了解决这个问题,react 16 中提供了 componentDidCatch 方法,用于捕获组件中的渲染异常,这样当某个组件挂掉的时候,我们可以做针对性的处理,不至于整个页面瘫痪掉。

componentDidCatch的使用方式

react 官方提供了一个示例:demo

包装组件问题

从上面的示例可以得知,我们要想处理某个组件的渲染异常,需要做两件事,首先申明一个错误处理组件:

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

  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

然后包装我们需要处理的组件:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

一旦使用了这种包装方式,我们必须人工判断哪些组件应该做错误处理,哪些组件可以不做错误处理,这使得我们的业务代码里会混入很多错误处理的非业务代码:

<ErrorBoundary>
  <A>
    <B></B>
    <ErrorBoundary>
      <C></C>
    </ErrorBoundary>
    <D><E></E></D>
  </A>
</ErrorBoundary>

是否可以让我们编程的时候,能够专注于业务,摆脱这种包装代码呢?我们可以尝试下面的方式。

重写 React.createElement

我们可以通过重写 React.createElement ,将代码中的每个组件都包装一下:

const rc = React.createElement
React.createElement = (type, config, ...other) => {
    return rc(ErrorBoundary, keyObj, rc(type, config, ...other))
}

使用重写后的 React.createElement 效果:

<A>
  <B></B>
  <C></C>
  <D><E></E></D>
</A>

// 上面代码通过重写的 React.createElement 转化后变为:
<ErrorBoundary>
  <A>
    <ErrorBoundary><B></B></ErrorBoundary>
    <ErrorBoundary><C></C></ErrorBoundary>
    <ErrorBoundary>
      <D>
        <ErrorBoundary><E></E></ErrorBoundary>
      </D>
    </ErrorBoundary>
  </A>
</ErrorBoundary>

这样就可以统一处理渲染异常,而不会侵入我们的业务代码!

上一篇下一篇

猜你喜欢

热点阅读