This is the 11th day of my participation in the August More Text Challenge. For details, see:August is more challenging

In the previous section we have analyzed the key process from construction to rendering of the Fiber tree. In this section we take a look at the fiber object and consider how a specific fiber node affects the final render.

Reviewing the fiber data structure and the previous interpretation of the fiber tree structure series, we notice that among the fiber attributes, two types of attributes are critical:

  1. Fiber node’s own state: In the renderRootSync[Concurrent] phase, it provides certain input data to the child node and directly affects the generation of the child node.

  2. Side effects of the fiber node: During the commitRoot phase, if fiber is marked with side effects, the side effect related functions are called (synchronous/asynchronous).

export type Fiber = {|
  // 1. The fiber node is related to its own state
  pendingProps: any,
  memoizedProps: any,
  updateQueue: mixed,
  memoizedState: any,

  // 2. The fiber node is related to the Effect
  flags: Flags,
  subtreeFlags: Flags, // V17.0.2 is disabled
  deletions: Array<Fiber> | null.// V17.0.2 is disabled
  nextEffect: Fiber | null.firstEffect: Fiber | null.lastEffect: Fiber | null|};Copy the code

state

There are four attributes associated with the state:

  1. fiber.pendingProps: Input properties fromReactElementObject passed in. It andfiber.memoizedPropsThe comparison shows whether the attribute has changed.
  2. fiber.memoizedProps: property used the last time the child nodes were generated and kept in memory after generation. Before the generation of child nodes down is calledpendingPropsAfter the child nodes are generated, thependingPropsAssigned tomemoizedPropsFor the next comparison.pendingPropsandmemoizedPropsThe comparison shows whether the attribute has changed.
  3. fiber.updateQueue: storageUpdate Update objectEach time an update is initiated, you need to create one on this queueThe update object.
  4. fiber.memoizedState: Local state in memory since the last generation of child nodes.

Their functions are limited to the fiber tree construction stage and directly affect the generation of child nodes.

Side effects

There are four attributes associated with side effects:

  1. fiber.flags: Indicates the flag bitfiberNodes have side effects (defined in V17.0.2)28 side effects).
  2. fiber.nextEffect: One-way linked list, pointing to the next side effectfiberNode.
  3. fiber.firstEffect: One-way linked list, pointing to the first side effectfiberNode.
  4. fiber.lastEffect: One-way linked list, pointing to the last side effectfiberNode.

As we know from the previous fiber tree construction, the side effects queue of a single fiber node will eventually move up to the root node. So react provides three ways to handle side effects during the commitRoot phase (see Fiber Tree rendering).

In addition, the design of side effects can be understood as complementing the lack of state functionality.

  • stateIs astaticWhich can only provide data sources for child nodes.
  • whileSide effectsIs adynamicFunction, as it is called whenFiber tree rendering phaseSo it has more power and can be easily acquiredSnapshot before mutation, DOM node after mutation, etc.even throughCall APILaunch a new roundFiber tree structureAnd change even morestate, causing moreSide effects.

External API

These two types of properties of the fiber object can affect the render results, but the fiber structure is always a kernel structure, which is invisible to the outside world, and the caller does not even need to know that the fiber structure exists. Therefore, it is normal to modify these two types of properties directly or indirectly by exposing the API.

From the API exposed in the React package, there are only two types of components that support modification:

The purpose of using the API in this section is to modify the state and side effects of fiber, which in turn can change the overall rendering result. This section first introduces the connection between API and state and side effects. The specific implementation of API will be analyzed in detail in the class Component and Hook principles section.

The class components

class App extends React.Component {
  constructor() {
    this.state = {
      // Initial state
      a: 1}; } changeState =() = > {
    this.setState({ a: + +this.state.a }); // Enter the Reconciler process
  };

  // Life cycle function: state dependent
  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('getDerivedStateFromProps');
    return prevState;
  }

  // Life cycle function: state dependent
  shouldComponentUpdate(newProps, newState, nextContext) {
    console.log('shouldComponentUpdate');
    return true;
  }

  Function: / / life cycle side effects related to fiber. The flags | = Update
  componentDidMount() {
    console.log('componentDidMount');
  }

  Function: / / life cycle side effects related to fiber. The flags | = the Snapshot
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate');
  }

  Function: / / life cycle side effects related to fiber. The flags | = Update
  componentDidUpdate() {
    console.log('componentDidUpdate');
  }

  render() {
    // Return the subordinate ReactElement object
    return <button onClick={this.changeState}>{this.state.a}</button>; }}Copy the code
  1. State related: Fiber tree construction phase.

    1. Constructor:constructorWhen instantiated, you can set the initial state and execute it only once.
    2. Life cycle:getDerivedStateFromPropsinFiber tree structurePhase (renderRootSync[Concurrent]), you can modify the state(link).
    3. Life cycle:shouldComponentUpdateIn,Fiber tree structurePhase (renderRootSync[Concurrent]The return value determines whether to execute render(link).
  2. Side effects related: Fiber tree rendering stage.

    1. Life cycle:getSnapshotBeforeUpdateinFiber tree renderingPhase (commitRoot->commitBeforeMutationEffects->commitBeforeMutationEffectOnFiber) (link).
    2. Life cycle:componentDidMountinFiber tree renderingPhase (commitRoot->commitLayoutEffects->commitLayoutEffectOnFiber) (link).
    3. Life cycle:componentDidUpdateinFiber tree renderingPhase (commitRoot->commitLayoutEffects->commitLayoutEffectOnFiber) (link).

As you can see, the class component lifecycle functions provided by the official API are actually provided around the fiber tree construction and fiber tree rendering.

The function components

Note: The main difference between a function component and a class component is that a class component instantiates an instance so it has its own local state. The function component is not instantiated. It is called directly, so it cannot maintain an independent local state. It can only be implemented indirectly by Hook objects (for more details on implementing hooks, see Hook principles).

Fourteen kinds of hooks are defined in V17.0.2, among which the most commonly used ones are useState, useEffect, useLayoutEffect, etc

function App() {
  // State related: initial state
  const [a, setA] = useState(1);
  const changeState = () = > {
    setA(++a); // Enter the Reconciler process
  };

  / / side effects: fiber. The flags | = Update | Passive;
  useEffect(() = > {
    console.log(`useEffect`); } []);/ / side effects: fiber. The flags | = Update;
  useLayoutEffect(() = > {
    console.log(`useLayoutEffect`); } []);// Return the subordinate ReactElement object
  return <button onClick={changeState}>{a}</button>;
}
Copy the code
  1. Status related:Fiber tree structurePhase.
    1. useStateinFiber tree structurePhase (renderRootSync[Concurrent]) can be modifiedHook.memoizedState.
  2. Side effects related:Fiber tree renderingPhase.
    1. useEffectinFiber tree renderingPhase (commitRoot->commitBeforeMutationEffects->commitBeforeMutationEffectOnFiber(Note asynchronous execution,link).
    2. useLayoutEffectinFiber tree renderingPhase (commitRoot->commitLayoutEffects->commitLayoutEffectOnFiber->commitHookEffectListMount) execute (execute synchronously,link).

Details and pitfalls

Here are 2 details:

  1. useEffect(function(){}, [])Is the function ofAsynchronous execution, because it goes through the dispatch center (the implementation can be reviewedScheduling principle).
  2. useLayoutEffectandThe Class componentsIn thecomponentDidMount,componentDidUpdateIt’s equivalent in terms of call timing, because they’re both therecommitRoot->commitLayoutEffectsFunction is called.
    • Myth: Although the official website documentation recommends using standard ones whenever possibleuseEffectTo avoid blocking visual updates, so many developers use ituseEffectTo take the place ofcomponentDidMount,componentDidUpdateIt’s not accurate. If the exact analogy is,useLayoutEffectthanuseEffectMore in line withcomponentDidMount,componentDidUpdateThe definition.

To verify this conclusion, look at the example in CodesandBox.

conclusion

From the fiber perspective, this section summarizes two types of attributes (state and side effects) in the fiber node that can affect the final render result. It also summarizes the common ways that class and function components can directly or indirectly change the fiber property. Finally, from the perspective of fiber tree construction and rendering, the life cycle functions of class are compared with the Hooks functions of function.

Write in the last

This article belongs to the diagram react source code in the state management plate, this series of nearly 20 articles, really in order to understand the React source code, and then improve the architecture and coding ability.

The first draft of the graphic section has been completed and will be updated in August. If there are any errors in the article, we will correct them as soon as possible on Github.