10
头图

Hi everyone, I'm Kasong.

This article will explain the complete implementation logic of React in Error Boundaries

A picture summarizes:

Here is a brief explanation of the React workflow, which will be useful later. It is divided into three steps:

  1. Trigger update
  2. stage: Calculate the side effects caused by the 161a9b978b7e17 update
  3. commit stage: execute side effects in the host environment

There are many side effects , such as:

  • Insert DOM node
  • Execute useEffect callback

Okay, let's get into the topic.

Welcome to join human high-quality front-end framework group , take the flight

What are Error Boundaries

React provides two related error handling API :

  • getDerivedStateFromError : Static method, which provides an opportunity to render fallback UI
  • componentDidCatch : Component instance method, which provides an opportunity to record error information when an error occurs

Use these two API of ClassComponent often referred to Error Boundaries (boundary error).

In Error Boundaries of sons components all occurred in the within React workflow errors will be Error Boundaries capture.

Through the introduction at the beginning, we can know that the React workflow refers to:

  • render stage
  • commit phase

Consider the following code:

class ErrorBoundary extends Component {
  componentDidCatch(e) {
    console.warn(“发生错误”, e);
  }
  render() {
    return <div>{this.props.children}</div>;
  }
}

const App = () => (
    <ErrorBoundary>
    <A><B/></A>
    <C/>
    <ErrorBoundary>
)

A , B , C as ErrorBoundary descendants assembly occurs when the workflow React errors, will be ErrorBoundary in componentDidCatch capture method.

Step 1: catch the error

First look at when the errors in the when they are caught.

render stage is as follows, and errors that occur will be handled handleError

do {
  try {
    // 对于并发更新则是workLoopConcurrent
workLoopSync();
    break;
  } catch (thrownValue) {
    handleError(root, thrownValue);
  }
} while (true);

commit stage contains a lot of work, such as:

  • componentDidMount/Update execution
  • Bind/ ref
  • useEffect/useLayoutEffect callback and destroy execution

These tasks will be executed in the following form, and the errors that occur will be handled captureCommitPhaseError

try {
// …执行某项工作 
} catch (error) {
  captureCommitPhaseError(fiber, fiber.return, error);
}

Step 2: construct a callback

It can be found that even if there is no Error Boundaries , the error in the workflow has been caught React The correct logic should be:

  • If Error Boundaries exists, execute corresponding API
  • Throw out the React
  • Error Boundaries does not exist, throw uncaught error

Therefore, whether it is handleError or captureCommitPhaseError , it will start from the parent node of the node where the error occurred, and traverse up layer by layer, looking for the nearest Error Boundaries .

Once found, it will construct:

  • For execution Boundaries API Error of callback
  • For throw React message of callback

React错误提示信息,包括提示语和错误堆栈

  // ...为了可读性,逻辑有删减
function createClassErrorUpdate() {
  if (typeof getDerivedStateFromError === 'function') {
// 用于执行getDerivedStateFromError的callback
    update.payload = () => {
      return getDerivedStateFromError(error);
};
// 用于抛出React提示信息的callback
    update.callback = () => {
      logCapturedError(fiber, errorInfo);
    };
  }
  if (inst !== null && typeof inst.componentDidCatch === 'function') {
// 用于执行componentDidCatch的callback
    update.callback = function callback() {
      this.componentDidCatch(error);
    };
  }
  return update;
}

Error Boundaries is not found, continue to traverse up to the root node.

This will construct:

  • For throw uncaught error of callback
  • For throw React message of callback
// ...为了可读性,逻辑有删减
funffction createRootErrorUpdate() {
  // 用于抛出“未捕获的错误”及“React的提示信息”的callback
  update.callback = () => {
    onUncaughtError(error);
    logCapturedError(fiber, errorInfo);
  };
  return update;
}

Execute callback

When will the constructed callback be executed?

In React two in execute user-defined callback of API :

  • For ClassComponent , this.setState(newState, callback) and callback parameters in newState can be passed Function as callback

Therefore, for Error Boundaries , it is equivalent to actively triggering an update:

this.setState(() => {
  // 用于执行getDerivedStateFromError的callback
}, () => {
  // 用于执行componentDidCatch的callback
  //  以及 用于抛出React提示信息的callback
})
  • For the root node, execute ReactDOM.render(element, container, callback) parameter in callback to pass Function as callback

Therefore, for without Error Boundaries , it is equivalent to actively executing the following functions:

ReactDOM.render(element, container, () => {
// 用于抛出“未捕获的错误”及“React的提示信息”的callback
})

Therefore, Error Boundaries can be regarded as: React utilizes the new functions realized by API

Summarize

People often ask: Why is Hooks not Error Boundaries ?

You can see, Error Boundaries achieved by means of a this.setState can pass callback characteristics, useState temporarily unable to complete benchmarking.

Finally, you leave a job, in official document describes four cases of error will not be Error Boundaries captured.

Using the knowledge of this article, can you analyze why they were not captured?


卡颂
3.1k 声望16.7k 粉丝