One, foreword

Again yue four season, the job recently and holding the test their learning outcomes of the state of mind in a certain factory, see oneself are several catties several two, here are sharing a question in a job interview, it is the research value, personal think through this question can test what you know about the React of render exactly, first put questions to the following:

const Child = () = > {
  console.log("Child");
  return (
    <div className="child" title="child">
      Child
    </div>
  );
};
const Parent = (props) = > {
  const [count, setCount] = useState(0);
  return (
    <div
      className="parent"
      title="parent"
      onClick={()= > setCount((pre) => pre + 1)}
    >
      {props.children}
    </div>
  );
};
function App() {
  return (
    <div className="App">
      <Parent>
        <Child />
      </Parent>
    </div>
  );
}
Copy the code

The question is how many times will console.log in the Child component render between the time the page is first entered and the time the onClick event is triggered three times?

Answer: once

Second, pre-knowledge

1, the React. CreateElement method

We know that for JSX code it will eventually be compiled by Babel into the form react.createElement (type, config, children) (the new JSX conversion has been used since React17), These functions are executed during the Render phase, which returns a JSX object, such as the following JSX code:

<div className='class' title='title'>
  <p>xiling</p>
</div>
Copy the code

Babel compiled as follows:

React.createElement("div", {
  className: "class".title: "title"
},React.createElement("p".null."xiling"));
Copy the code

React.createElement returns the following value:

Among themtypeProperty represents the type of the current element, in this case the div tag,propsAttribute classes hold attributes defined in the element, such as className, title, children, and so on. So here’s the question: what does this JSX object do when it’s so complex? In fact, this JSX is implementationdiffOne of the key elements of the algorithm is that the JSX code we write is eventually converted into a JSX object that describes the code information. In the DiFF algorithm React compares the information on the Fiber node to the JSX object to determine if it needs to be updated.

2. Fiber node creation method

There are two ways to create a Fiber node:

  1. Generate fiber nodes from JSX objects returned by Render on first rendering.

Take the div element in the App component. On the left is the JSX object corresponding to the div, and on the right is the final Fiber node. The most important point is highlighted in red. The pendingProps attribute of the fiber node holds the same information as the props attribute of the JSX object, fiber. PendingProps === jsx. props We can verify this by looking at the createFiberFromElement method:


function createFiberFromElement(element, mode, expirationTime) {
  var owner = null;
  {
    owner = element._owner;
  }
  var type = element.type;
  var key = element.key;
  // Assign
  var pendingProps = element.props;
  var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime);
  {
    fiber._debugSource = element._source;
    fiber._debugOwner = element._owner;
  }
  return fiber;
}
Copy the code
  1. If ubiquitously hit during update, the last updated Fiber node could be reused directly, and the component would not execute its Render method.

    By now I’m guessing you know why. The Child component must take this path, and it does. Now we need to figure out when to take this path.

    First we need to know that there are two child stages in the Render phase, of which the beginWork is called the recursive phase, which starts from the root node of the application and then creates the child node of the root node, and then creates its child node from the child node to the leaf node, After this phase, a complete fiber tree was generated, and the beginWork method showed several conditions for entering Bailout:

  1. oldProps === newProps

PendingProps is the same as JSX props. When do oldProps and newProps want to wait? CreateElement generates new props every time a component/element executes the React.CreateElement generates new props even if the data inside it remains the same.

  1. The Context hasn’t changed

When we use createContext for data transfer, if the data in it changes, the components that consume that data are re-rendered.

  1. updateExpirationTime < renderExpirationTime

If the current Fiber node has the same update priority as the React dispatch, it will be rerendered. Click onClick to see the priority of the Parent fiber node:

We find that the two priorities are the same, indicating that the Parent component should enter the Render logic.

Third, Bailout stage

Must first know Bailout is certainly occur at the time of the update, and to create mounted period fiber node is all said that the first way above, we according to our the given examples will be mounted after fiber tree drawn:

At this point our workInProgress tree has only one root node, and when we trigger the onClick event an update will be made, which means creating a new Fiber tree, Before entering beginWork, we need to call createWorkInProgress, which is the entry to create the workInprogress Fiber tree. Let’s see what’s going on inside.

We see that he is actually defining some properties of workInProgress, which is the rootFiber node in the workInProgress Fiber tree, The key step is to assign current. Child to workInProgress, so the fiber tree looks like this:

The WorkInProgress Fiber tree begins with the rootFiber node of the WorkInProgress tree, which is the root node of the current application. At this point, his alternte pointer points to the rootFiber node of the current tree, as shown below:

This is the node that fulfills all three conditions of Bailout, so when you get to Bailout, in the beginWork function you end up inbailoutOnAlreadyFinishedWorkThe function creates the child node of rootFiber. Let’s see what it does:

function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) {
    / /... Ignore the unimportant
    cloneChildFibers(current$$1, workInProgress);
    returnworkInProgress.child; }}Copy the code

Here we see that it calls the cloneChildFibers method and then returns the workinProgress.child. Assign a property from the current child to the child of workInProgress

function cloneChildFibers(current$$1, workInProgress) {
  / /...
  Workinprogress. child = workinProgress. child = workinProgress. child = workinProgress. child = workinProgress. child
  var currentChild = workInProgress.child;
  // Create a new Fiber node, where the pendingProps is the same as the pendingProps on the current
  var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime);
  // Assign the newly created newChild to workinprogress.child
  workInProgress.child = newChild;
  newChild.return = workInProgress;
  / /...
}
Copy the code

Let’s see what happens to our fiber tree after executing this function

That is to say, the two divs have alternate links between them, and their pendingProps are the samecurrent.memoizedPropsIn fact, iscurrent.pendingProps, so the fiber corresponding to the div will also goBailout, until the fiber corresponding to the Parent component enters the beginWork, at this time, because the Parent component has been updated, it cannot goBailoutHe needs to call React.CreateElement to regenerate the corresponding JSX object and then perform the Diff operation.

But what does this process have to do with our problem? And the answer is already there, for this form:

{props.children}
Copy the code

This object represents the JSX object corresponding to the Child component. The props property corresponds to the pendingProps property on the Fiber node of the Parent component. This property is unchanged before and after the update. The extension of the fiber node also satisfies the oldProps === newProps, which would satisfy the Bailout condition, and therefore would not render.

portal

  • I don’t know how TypeScript looks up type definitions. Okay
  • That’s all you need to know about Docker theory
  • Mobx and Redux came to me
  • Tree-shaking in-depth parsing