4
头图

Hello everyone, I'm Casson.

In many comprehensive use Hooks development team, the only use ClassComponent scene is to use ClassComponent to create ErrorBoundary .

It can be said that if Hooks there are alternatives to the following two lifecycle functions, it can completely abandon ClassComponent :

  • getDerivedStateFromError
  • componentDidCatch

Then why hasn't the target Hook yet?

Today we will discuss this issue from the implementation principles of the above two life cycle functions and the cost of porting to Hook .

Welcome to join the human high-quality front-end framework group , with flying

ErrorBoundary implementation principle

ErrorBoundary can catch errors within React workflows in descendant components.

React workflow refers to:

  • The render stage, that is, the stage where the component render and Diff algorithm occur
  • The commit stage is the stage where the DOM is rendered and the componentDidMount/Update is executed

This is also why errors that occur in event callbacks cannot be caught ErrorBoundary event callbacks are not part of the React workflow .

How to catch errors

The overall execution flow of the render phase is as follows:

 do {
  try {
    // render阶段具体的执行流程
    workLoop();
    break;
  } catch (thrownValue) {
    handleError(root, thrownValue);
  }
} while (true);

It can be found that if an error occurs in the render stage , it will be captured and executed handleError method.

Similarly, the overall execution flow of the commit phase is as follows:

 try {
  // ...具体执行流程
} catch (error) {
  captureCommitPhaseError(current, nearestMountedAncestor, error);
}

If an error occurs in the commit phase , it will be caught and executed captureCommitPhaseError method.

getDerivedStateFromError principle

How to deal with the error after catching it?

We know that the first parameter of ClassComponent in this.setState can receive not only a new state , but also a function that changes the state as a parameter:

 // 可以这样
this.setState(this.state.num + 1)

// 也可以这样
this.setState(num => num + 1)

The realization of getDerivedStateFromError this.setState on the feature of the function that changes the state in ---dcfbf84c5967beb9ba43a57e78f733a1---.

When the error is caught, that is:

  • For the render stage , handleError after execution
  • For the commit stage , captureCommitPhaseError after execution

It will trigger an update similar to the following in the corresponding component ErrorBoundary :

 this.setState(
  getDerivedStateFromError.bind(null, error)
)

That's why getDerivedStateFromError asks the developer to return to a new state -- essentially, he triggers a new update.

componentDidCatch principle

Let's look at another ErrorBoundary related lifecycle functions componentDidCatch .

ClassComponent this.setState The second parameter of ---d13dce8775b35ac32accb875b1cb9656--- can receive a callback function as a parameter:

 this.setState(newState, () => {
  // ...回调
})

The callback fires when the triggered update is rendered to the page.

This is how componentDidCatch is implemented.

When the error is caught, an update similar to the following will be triggered in the corresponding component ErrorBoundary :

 this.setState(this.state, componentDidCatch.bind(this, error))

Handling "uncaught" errors

It can be found that the errors in the React running process have been captured by React itself, and then handed over to ErrorBoundary for processing.

If ErrorBoundary is not defined, these caught errors need to be re-throwed, giving the impression that the error was not caught .

Where is this step performed?

Similar to this.setState , ReactDOM.render(element, container[, callback]) the third parameter can also receive a callback function .

If the developer does not define ErrorBoundary , then React will eventually throw an error in the callback of ReactDOM.render .

It can be found that the implementation of ClassComponent in ErrorBoundary completely depends on the existing features of ClassComponent .

And Hooks itself does not have a callback feature similar to this.setState , so it will be more complicated to implement.

Implement ErrorBoundary in Hooks

In addition to the obstacles mentioned above, FunctionComponent and ClassComponent also have differences in the details of the operating process at the source code level, and it is difficult to copy and implement.

If it must be implemented, useErrorBoundary (the implementation of ErrorBoundary in Hooks ) should be used under the guidelines of maximizing reuse of existing infrastructure Similar to the following:

 function ErrorBoundary({children}: {children: ReactNode}) {
  const [errorMsg, updateError] = useState<Error | null>(null);

  useErrorBoundary((e: Error) => {
    // 捕获到错误,触发更新
    updateError(e);
  })

  return (
    <div>
      {errorMsg ? '报错:' + errorMsg.toString() : children}
    </div>
  )
}

The triggering method of ---6bc4d66a91c39dd4dc161dcc18686023 useErrorBoundary is similar to useEffect :

 useErrorBoundary((e: Error) => {
  // ...
})

// 类似
useEffect(() => {
  // ...
})

ClassComponentErrorBoundary原理与useEffect原理,实现了原生Hooks —— useErrorBoundary

Interested friends can experience the effect in the useErrorBoundary online example .

Summarize

ErrorBoundary ClassComponent使用了---e8bdfc99e978542ee1b58972a464b4dd this.setState的回调函数特性,这使得---714bb9a59d380700dee8ee1f5a91407a Hooks Development costs.

The author guesses that this is one of the reasons why the corresponding native Hooks is not provided.


卡颂
3.1k 声望16.7k 粉丝