Today, we have a funny question from our React source group. If you think you understand the React process well, you can check it out.

For the following Demo, click on the Parent component’s div to trigger the update and the Son component prints Child Render! ?

function Son() {
  console.log('child render! ');
  return <div>Son</div>;
}

 function Parent(props) {  const [count, setCount] = React.useState(0);   return (  <div onClick={()= > {setCount(count + 1)}}>  count:{count}  {props.children}  </div>  ); }   function App() {  return (  <Parent>  <Son/>  </Parent>  ); }  const rootEl = document.querySelector("#root"); ReactDOM.render(<App/>, rootEl); Copy the code

Online Demo Address

👉 right click to show the answer: NoCopy the code

Conditions render needs to satisfy

When React creates the Fiber tree, the Fiber for each component is created using one of two logics:

  • Render. Call the Render function to create a new fiber based on the returned JSX.

  • Bailout. That is, when certain conditions are met, React determines that the component has not changed before and after the update, and reuses the fiber updated last time as the fiber updated this time.

As you can see, the render function is not called when the bailout logic is hit.

Therefore, the Son component does not print Child Render! Because we hit bailout logic.

Bailout needs to meet the conditions

Now, when does bailout logic come into play? When the following four conditions are met:

1. OldProps === newProps?

That is, the props (newProps) updated this time is not equal to the props (oldProps) updated last time.

Notice that this is congruent comparison.

We know that the component Render returns JSX, which is the syntactic sugar for react. createElement.

So the result of render is actually an execution of React. CreateElement, which is an object containing the props property.

This update is the result of the React. CreateElement, which is a new reference to the oldProps. = = newProps.

If we use PureComponent or Memo, we will not judge whether oldProps and newProps are congruent when we enter Render or bailout. Instead, we will perform a shallow comparison of each attribute in the props.

2. The context does not change

The value of the context doesn’t change.

3. Workinprogress.type === current. Type?

Does fiber.type change before and after the update, e.g. does div change to P?

4.! IncludesSomeLane (renderLanes, updateLanes)?

Is there an update on the fiber tree, and if so, is the priority of the update consistent with that of the entire fiber tree?

If they do, the render logic is entered.

For our Demo, Parent is the only component in the entire tree that can trigger an update (by calling setCount).

Therefore, the fiber corresponding to Parent is the only fiber that satisfies condition 4.

Detailed execution logic of Demo

Therefore, Son entered bailout logic in the Demo, which must satisfy the above four conditions at the same time. Let’s look at them one by one.

Condition 2, we didn’t use the context in the Demo, so it works.

Condition 3, the type before and after the update is the function component corresponding to Son, which is satisfied.

Condition 4, Son itself cannot trigger the update, satisfied.

So, the point is condition 1. Let’s take a closer look.

At the beginning of this update, the Fiber tree has the following 2 fibers:

FiberRootNode
      |
  RootFiber      
Copy the code

Where FiberRootNode is the root node of the entire application, RootFiber is the fiber created by calling Reactdom.render.

First, RootFiber will enter the bailout logic, so the App Fiber returned is the same as before update.

FiberRootNode
      |
  RootFiber      
      |
  App fiber
Copy the code

App Fiber oldProps === newProps And the other three conditions were also satisfied.

So App Fiber would also go back to Parent fiber.

FiberRootNode
      |
  RootFiber      
      |
   App fiber
 |  Parent fiber Copy the code

Since the update is triggered by the Parent Fiber, it does not satisfy condition 4 and will use render logic.

Here’s the key

If Render returns Son of the form:

<Son/>
Copy the code

Will be compiled into

React.createElement(Son, null)
Copy the code

Return JSX after execution.

Due to a reference change to props, oldProps! = = newProps. Can do render logic.

But in the Demo Son is in the following form:

{props.children}
Copy the code

Where, props. Children is the JSX corresponding to Son, and the props is returned after App Fiber bailout logic.

Therefore, the JSX corresponding to Son is the same as that in the last update, and the props saved in JSX are the same, which meets condition 1.

As you can see, Son satisfies all the conditions of bailout, so it won’t render.

conclusion

Once you understand these four conditions, you’ll have a whole new understanding of the React component update.

I have to say React was so hard that the workers shed tears.

Pay attention to the public number, into the source group, and other front-end workers grow up together.