Reprinted fromScratch the surface, how does React work

Big god can write “simple” series, small white will write point “really · shallow tasted” series of it, mainly for their own understanding and consolidation, after all, the source code will still be a big drop, so ready to dabble under the understanding of “React how to work?”

How does React work? Do you know the Diff algorithm –xx interviewer

Small white front drain guide:

1.VK’s Adventures in Autumn Recruitment (1)

2.VK’s Adventures in autumn Recruitment (2)

3.VK’s Adventures in autumn Recruitment (3)

4. Front-end interview & written test Algorithm

How React.js works

Virtual Dom VS Browser Dom

In addition to being an MVC framework and data-driven page feature, React is “fast” at its core. As the common saying goes: “Because direct manipulation of the DOM involves redrawing, backflow, etc., there is a huge performance drain and rendering slowness. React uses the virtual DOM. After each state update, React compares the differences between the virtual DOM and changes the content. Finally, React modifies the real DOM and completes the page update and rendering.

React/React/React/React/React/React Diff algorithm?” . I had a bit of a breakdown, so I decided to dabble:

  • At the heart of React is the virtual DOM, which is essentially a JavaScript object.
  • BrowserDOM(the actual DOM of a page) is the Browser object.

There is little to say about DOM, but here are some features of the virtual DOM:

  1. Essentially a JS object that represents the real DOM
  2. Much faster than real DOM comparison and manipulation
  3. 200,000 virtual DOM nodes can be created per second
  4. Each time setState or despatch an action, a new virtual DOM is created

React creates a new Virtual DOM based on the current state.

Here, whenever the Virtual DOM is generated, it is printed out. As you can see, it represents the real DOM, and every time a new ONE is generated, it is also possible to compare the old DOM with the new DOM.

The Diff algorithm

React captures the content in each state, generates a new Virtual DOM, and compares it to the previous one to find differences. The React Diff algorithm has two conventions:

  1. Two different types of elements produce two different trees
  2. Developers can use the key keyword to tell React which child elements are stable and unchanging under the DOM.

For example, the ul tag of the real DOM has a list of

  • tags. However, when you rearrange the tags, if you give each tag a key value, React will know that “you are still you, but in a different position.” React wants change to be minimal in addition to finding the difference fastest. If you add a key, React keeps the instance, rather than creating a completely new DOM as it did before.
  • Let’s be more specific:

    1234

    After the next state, the sequence becomes

    1243

    For us, we’re just switching the order of the 4 and the 3. How do you let React know that the old 3 is behind the old 4? That’s the only key that works.

    Why do React list templates include keys

    Diff operation instance

    Diff compares the two root elements first, which may take more effort when the difference is a type change

    Different types of DOM elements

    For example, the state now has a change like this:

    <div>
        <Counter />
    </div>
    
          
    Copy the code

    <span> <Counter /> </span> Copy the code

    As you can see, from

    to
    , this type of change directly destroys the entire old tree, including the child element Counter. So the old instance Counter will be completely destroyed and a new instance will be created, which is obviously inefficient

    Dom element of the same type

    React will look at the properties and modify them directly, leaving the original instance intact to make rendering more efficient. For example:

    <div className="before" title="stuff" />
    Copy the code

    <div className="after" title="stuff" /> Copy the code

    In addition to classnames, including style, additions, deletions, and changes do not destroy the entire DOM tree. Instead, attributes are modified, preserving the elements and nodes below them

    Component elements of the same type

    As above, the strength of the child element of the same type of component element is maintained, not destroyed. When a component is updated, the instance remains unchanged in order to maintain state between renders. React to update the underlying component instance of props to match the new elements, and calls on the underlying instance componentWillReceiveProps () and componentWillUpdate ().

    Next, the Render () method is called, and the diff algorithm recurses over the previous result and the new result

    key props

    If the previous explanation of key wasn’t clear enough, let’s use a real example to illustrate the importance of keys.

    • Scenario 1: Add an element at the end of a list
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    ------
    <ul>
      <li>first</li>
      <li>second</li>
      <li>third</li>
    </ul>
    Copy the codeCopy the code

    In this case, React only needs to insert a new element at the end, and nothing else needs to change. React is efficient, but in scenario 2:

    • Scenario 2: Insert an element at the top of the list
    <ul>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    ---
    <ul>
      <li>Connecticut</li>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    Copy the codeCopy the code

    This could be disastrous for React, because React only knows that the first two elements are different, so it completely innovates a new element and ends up recreating all three elements, which greatly reduces efficiency. This is where key comes in handy. When a child element has a key, React uses the key to match the child element in the original tree with the child element in the subsequent tree. For example, adding a key to the inefficient example above would make tree conversion more efficient:

    <ul>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>
    ------
    <ul>
      <li key="2014">Connecticut</li>
      <li key="2015">Duke</li>
      <li key="2016">Villanova</li>
    </ul>
    Copy the codeCopy the code

    Thus, only the key values of 2014 are newly created, while 2015 and 2016 are simply moved.

    strategy

    What strategy does React use to compare the difference between two trees? This strategy is the core:

    The complete diff algorithm for two trees is an O(n^3) time complexity problem. But in the front end, you rarely move DOM elements across hierarchies. So the Virtual DOM only compares elements at the same level:

    The upper div will only be compared to divs of the same level, and the second level will only be compared to the second level. So that’s order n.

    Depth-first traversal

    In real code, a depth-first traverse of the old and new trees would be performed so that each node would have a unique mark, and then the differences would be recorded

    In depth-first traversal, each time a node is traversed, the node is compared to the new tree. If there is a difference, it is recorded in an object.

    For example, node P 1 in the first figure has a change, which is recorded as follows:

    patches[1] = [{difference}, {difference}...]// Use an array to store the differences between the old and new nodes
    Copy the codeCopy the code

    Ok, so what about the difference types, as mentioned in the previous section, which are divided into two categories, including the types of the root element, and then adopt different replacement strategies depending on the situation.

    Finally, it’s time to apply the differences, update and render in the real DOM.


    Why does Redux need reducers to be pure?

    This is another serious problem. As anyone who uses Redux knows, reducers will take the previous state and action as arguments and return a new state that cannot be modified from the original state. So you often see the following:

    return Object.assign(...)
    / / or -- -- -- -- -- -- -- -- -- --
    return{... state,xx:xxx}
    Copy the codeCopy the code

    All it does is return a brand new object.

    Why are reducers required to be pure functions (returning entirely new objects without affecting the original ones)? — An interviewer

    Pure functions

    In essence, pure functions are defined as follows: do not modify the input value of the function, depend on external state (such as database, DOM, and global variables), and have the same output for any identical input.

    For example, the following add function does not modify variables A or B, does not depend on external state, and always returns the same result for the same input.

    const add = (a,b) = > {a + b};
    Copy the codeCopy the code

    This is a pure function, and the result has no influence on A and B. Turn to reducer, it meets all features of the pure function, so it is a pure function

    Why does it have to be pure?

    Let me tell you the result first. If I had done something on the original state in reducer and returned it, React would not have been re-rendered. Nothing will change at all!

    Take a look at Redux source code:

    Redux receives a given state (object) and passes each part of the state through a loop to each corresponding Reducer. If anything changes, the Reducer returns a new object. If nothing changes, the Reducer returns the old state.

    Redux compares the old and new objects only by comparing their storage locations. If you modify the attribute values of the old state object directly inside the Reducer, the new state and the old state will both point to the same object. Redux therefore assumes that nothing has changed and that the returned state will be the old state.

    Well, that is, from a source code perspective, Redux requires developers to make new states completely new objects. So why bother developers?

    Look at the following example: Try to compare whether a and B are the same

    var a = {
        name: 'jack'.friend: ['sam'.'xiaoming'.'cunsi'].years: 12.// omit the n item
    }
    Copy the code

    var b = { name: 'jack'.friend: ['sam'.'xiaoming'.'cunsi'].years: 13.// omit the n item } Copy the code

    What’s the idea? We need to iterate over the object, and if the object’s property is an array, we need to recursively iterate over it to see if it’s consistent and if it’s changed. The performance penalty is huge. Is there a better way?

    There are!

    // Follow the example above
    a === b  //false
    Copy the codeCopy the code

    I don’t want to make a deep comparison, just a shallow comparison. If the reference value is different (not the same object), it is different. This is why the Reducer of Redux was designed this way

    The resources

    1. Why does Redux need reducers to be pure

    2. In-depth analysis: How to implement a Virtual DOM algorithm

    3.Learn how to code: how react.js works