This article is used to record the React principle learned recently. If there is any mistake or not strict, please correct it. Thank you very much. If you like or have some inspiration, welcome to like, to the author is also a kind of encouragement. If there are any React related principles, please leave a comment and I will continue to update. Thank you 🙏

Synthetic events

Event delegation

For more DOM events see juejin.cn/post/684790…

A bit of pre-knowledge: event delegation. Event delegates utilize event bubbling to merge the same event handling of child elements onto parent elements for unified processing. Example 🌰 : in the following UL, click each LI label to print the contents of the LI label.

<ul id="poem">
    <li>The moon is shining before the window</li>
    <li>Suspected frost on the ground</li>
    <li>Looking up, I find the moon bright</li>
    <li>Bowing, In homesickness I'm drowned</li>
</ul>
<script>
    const liList = document.getElementsByTagName("li");
    for(let i=0; i<liList.length; i++){ liList[i].addEventListener("click".function(e){
            console.log(e.target.innerHTML); })}</script>
Copy the code

The above is a crude implementation. Using event delegates, we can unify the logic of click on the parent ul element as follows:

const ul = document.getElementById("poem");
ul.addEventListener("click".function(e){
    console.log(e.target.innerHTML);
})
Copy the code

Synthetic events

If you think your will be bound to the native DOM element button, you are wrong.

In fact, just print addChange = (e)=>{console.log(e); } the prototype object for E is the SyntheticEvent class, not the MouseEvent object.

React SyntheticEvent (SyntheticEvent) is a custom event object that simulates all the capabilities of React native DOM events, and can be understood as a cross-browser wrapper for browser native events. It defines synthesized events according to the W3C specification, is compatible with all browsers, and has the same interface as browser native events.

The principle of compositing events is to unify events on the DOM node document through event delegation by using event bubbling.

Composite events are intended to be executed across browsers for better cross-platform. React also introduces an event pool to avoid frequent binding and unbinding events, facilitating unified event management and a transaction mechanism (described below).

React synthesized events are different from DOM native events, so do not mix them. React syntheses the event e.topPropagation (); Does not prevent native DOM events from bubbling up.

class setStateDemo extends React.Component{
    render(){
        return <div>
            <div onClick={this.clickDiv}>
                <button onClick={this.addChange}>cumulative</button>
            </div>
        </div>
    }

    clickDiv = () = >{
        console.log("div clicked");
    }
    
    addChange = (e) = >{
        e.stopPropagation();
        console.log("btn clicked");
   }
    bodyClickHandler = (e) = >{
        console.log("bodyClickHandler");
    }
    componentDidMount(){
        document.body.addEventListener('click'.this.bodyClickHandler);
    }
    componentWillUnmount(){
        document.body.removeEventListener('click'.this.bodyClickHandler)
    }
}
Copy the code

The final issue is the sequence of React events versus native events. To jump to the conclusion, you can write code to test:

  • React All events are mounted on the Document object;
  • When the actual DOM element fires the event, it bubbles up into the Document object and processes the React event.
  • So the React event is handled after the native event is executed;
  • Finally, the event mounted on document is actually executed.

Zhuanlan.zhihu.com/p/25883536 www.jianshu.com/p/fb3199e75… Blog.csdn.net/qq_36380426…

SetState is synchronous or asynchronous

First to an interview question pressure, ha ha ha 🤣

class Test extends React.Component {
  state  = {
      count: 0
  };
  componentDidMount() {
    this.setState({count: this.state.count + 1});
    console.log(this.state.count);

    this.setState({count: this.state.count + 1});
    console.log(this.state.count);

    setTimeout(() = > {
      this.setState({count: this.state.count + 1});
      console.log(this.state.count);

      this.setState({count: this.state.count + 1});
      console.log(this.state.count);
    }, 0);
}
  render() {
    return null; }};Copy the code

What is the output from above? So let’s keep it in suspense and keep going.

The setState design incorporates asynchronous updates. Why merge asynchrony? This.setstate ({count: this.state.count + 1}); Executed twice, the page would have refreshed twice without the merge asynchrony. Twice, if you do 10,000, 100,000 assignments in a for loop, the page is not going to crash. So instead of triggering an update immediately, setStates are merged and updated “when the time is right.” When is “ripe”? There is a variable isBatchingUpdates to control whether the value of state is updated. The specific logic is as follows:

If isBatchingUpdates are true, the value of setState will be used to determine the next operation. If isBatchingUpdates are true, the value of setState will be cached and not updated. When isBatchingUpdates are false, the state value is updated in a loop that updates all components of the dirtyComponents.

React has quietly set isBatchingUpdates to true before the React composite events and lifecycle hook functions are executed. This ensures that setState operations are merged and that frequent state changes are avoided, resulting in frequent backflow and redrawing of the page.

SetTimeout and setInterval are macro tasks. React has already completed a waiting round. If isBatchingUpdates have been changed to false, setState will trigger a direct change to state.

On the other hand, for native events, there is no React encapsulation or interception, and isBatchingUpdates cannot be updated to true. This causes isBatchingUpdates to be only false and executed immediately. So updates are synchronized in native events like addEventListener, setTimeout, and setInterval.

What’s the merge logic for setState? Back to the interview questions above, the console will output 0, 0, 2, 3

Why is that?

this.setState({count: this.state.count + 1});
console.log(this.state.count);

this.setState({count: this.state.count + 1});
console.log(this.state.count);
Copy the code

SetState ({count: this.state.count + 1}); setState({count: this.state.count + 1}); setState({count: this.state.count + 1}); This.state. count is 0, so it is equivalent to executing:

this.setState({count: 1});  
this.setState({count: 1});
Copy the code

After 0, for setTimeout, we know isBatchingUpdates are already false, so this.state.count will be changed immediately. So it’s going to print 2 and 3

Don’t want to be merged

How can setState not be “merged”? We could pass a function to setState that operates on previous data instead of on this.state.count:

addFn = () = >{
    this.setState((prevState, props) = >{
        return{
            count: prevState.count + 1}});this.setState((prevState, props) = >{
        return{
            count: prevState.count + 1}}); }Copy the code

What is the JSX

What is JSX? What is JSX? What is JSX? 😂 The soul triad asks.

JSX is a syntactic extension of JavaScript that is close to the template language, but has full JavaScript capabilities.

The React website provides the following definition. We can speak in plain English: JSX is a syntax extension of JavaScript that acts as a template, similar to Vue’s template.

JSX cannot escape without Babel. We can escape JSX code from Babel as follows:

Babel translates JSX into a function call called react.createElement (). We can understand that JSX is the syntactic sugar of the react.createElement () function. Instead of using the react.createElement () function to mumble the various parameters needed to write the react.createElement () function, JSX syntax presents the “template” we want to express in a way that is universally acceptable, cheap to learn, and has a clear parent-child structure.

What does the react.createElement () function return? It’s the React element, or virtual DOM.

  • React.createElement(); The React element () function generates the React element virtual DOM.
  • ReactDOM.render(); The function is responsible for converting the virtual DOM to the real DOM.

Why does the class component bind this

Add = this.add.bind(this); add = this.add.bind(this); add = this.add.bind(this); Bind this to the add function. Why is that?

class Counter extends React.Component{
    constructor(props){
      super(props);
      this.state = { count: 0};
      this.add = this.add.bind(this);
    }
    add(){
        this.setState({
            count: this.state.count + 1
        });
    }
    render(){
        return (
            <div>
                <button onClick={this.add}>Ordinary + 1</button>
            </div>)}}Copy the code

For ES6 to run in strict mode, let’s first look at the simple logic this points to in strict mode:

"use strict";
function a(){
  console.log(this);
}
a();
console.log(this);
Copy the code

In strict mode, global this points to window; This refers to undefined in the function.

"use strict";
class Counter{
    constructor(){
        this.name = "Tom";
    }
    say(){
        console.log(this); }}const c = new Counter();
c.say();
const sayTmp = c.say;
sayTmp();
Copy the code

Call the say method on instance C of Counter, and you can see that this refers to instance c.(The new operator changes this to juejin.cn/post/692309… Detailed introduction.)

But if we assign sayTmp as a variable, we’ll see that this is undefined. This is also expected. The sayTmp function does not refer to any variable, so it is undefined.

We already know that JSX will eventually be escaped as the react.createElement () function call, generating the virtual DOM, and then reactdom.render (); Function renders to the page. The Counter component will be escaped as follows:

"use strict";
class Counter{
    constructor(){
        this.name = "Tom";
    }
    say(){
        console.log(this);
    }
    render(){
        createElement(this.say); }}/ / simulation ReactDOM. Render ();
const createElement = function(cur){
    const p = document.createElement("p");
    p.innerHTML = "react dom";
    p.addEventListener("click".function(){
        cur();
    });
    document.body.append(p);
}

new Counter().render();
Copy the code

When we click on the p element on the page, the bound click event is executed. Cur is inserted, which is equivalent to const cur = this.say; . And then you call cur and you find that this is undefined. Because of this, we need to bind this to this.say in the constructor of Counter.

The life cycle

First up a comparatively full React life cycle figure address: projects. Wojtekmaj. Pl/React – lifec…

Here we introduce the React lifecycle process after 16.4. ComponentDidMount shouldComponentUpdate componentWillUnmount There are eight related functions, Constructor, getDerivedStateFromProps, Render, componentDidMount, shouldCompopnentUpdate, getSnapshotBeforeUpdate, ComponentDidUpdate, componentWillUnmount

Mount the stage

Constructor getDerivedStateFromProps Render componentDidMount

ComponentDidMount: componentDidMount is called after the component is loaded. At this point, we can get DOM nodes and manipulate them, such as operations on Canvas, SVG, server requests, and subscriptions. Remember to unsubscribe at componentWillUnmount.

Update the stage

The execution order is: getDerivedStateFromProps shouldCompopnentUpdate Render getSnapshotBeforeUpdate componentDidUpdate

ShouldComponentUpdate, componentDidUpdate

ShouldComponentUpdate (nextProps, nextState) : The default returns true. This triggers the execution of render and subsequent lifecycle functions. So by default a change in the parent’s state causes the child to go through the update process, even if the parent’s state is not passed to the child. If the subcomponent is rendering unnecessarily, we can optimize it using the PureComponent component, or add logic in shouldComponentUpdate(nextProps, nextState) to determine if the subcomponent is worth rendering again.

ComponentDidUpdate (newProps, newState, Snapshot) : a function triggered when component data is updated. The parameters are as follows: newProps: newProps newState: New State Snapshot: returned by getSnapshotBeforeUpdate

ComponentWillUnmount: Called when a component is unmounted or destroyed, we can use this function to clear timers, cancel network requests, clean up invalid DOM elements, etc

Why scrap some life cycles

The deprecated life cycle functions after React 16 are:

  • componentWillMount
  • componentWillReceviesProps
  • componentWillUpdate

These lifecycle functions precede Render and are in the “Render phase”, the appearance of the Fiber mechanism, which may be suspended, halted, or restarted by React. At the same time, developers sometimes do things like send requests in the above functions, which can result in requests being executed more than once. To avoid these dangerous operations, simply remove these redundant lifecycle functions.

Function component

React functions and classes are common implementations of components. Function components have no internal state and are often used as UI components for rendering purposes only. Functional components are also called stateless components.

Our class component is the extends React.Component implementation, which has built-in life cycle functions. Class components have significantly stronger capability boundaries than functional components.

Another important difference between the two is that function components capture state inside render, while class components do not; Function components really bind the data and render together.

React – overreacted. IO/How-are-fun – reacted -… Article comparing online example of classic: codesandbox. IO/s/pjqnl16lm…

The React principle of Hooks

React Hooks: juejin.cn/post/692715…

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class. Hooks do not work inside a class. But you can use them instead of classes.

What can a Hook do?

  • UseState (useState) in function components
  • Extract component state logic (custom hook)

Let’s start with the Use rules of React Hooks:

  • Use hooks only at the top level do not call hooks in loops, conditions, or nested functions. Make sure they are always called at the top of the React function, and make sure the hooks are called in the same order every render.

  • Only call the Hook in the React function, not in normal JavaScript functions.

React-hooks are the “Hooks” of the React component; introducing them in normal functions makes little sense. For the first one, why follow the hooks and get called in the same order every time you render?

In plain English, React Hooks are essentially a function that executes from first to last line of code every time state is changed. Hooks, at the bottom, rely on sequential linked lists for proper functioning. The first time the React Hooks function component is executed, multiple useState and useEffect functions are sequentially saved to the linked list. The second or NTH execution of the React Hooks function components and the useState and useEffect functions, in turn, look up the corresponding information from the cached linked list index. A change in the order (less or more) of a call to useState and useEffect can result in a list lookup error and bug.

If we want to conditionally execute an effect, we can put the judgment inside the Hook:

useEffect(function persistForm() {
    // 👍 places the conditional judgment in effect
    if(name ! = =' ') {
      localStorage.setItem('formData', name); }});Copy the code

React Hooks github.com/brickspert/…

Fiber Reconciler

Background:

React works in two stages:

  • React iterates through the new data recursively from the top down to generate new Virtual DOM, and then, through the Diff algorithm, finds the patches that need to be changed and places them in the update queue.
  • Renderer: Iterates through the update queue to actually update render elements by calling the host environment’s API. Host environments such as DOM, Native, WebGL, etc.

JavaScript is single-threaded, but browsers are multi-threaded. JavaScript threads and render threads are mutually exclusive; they cannot be executed interspersed and must be executed sequentially. When one thread executes, the other thread can only suspend and wait.

Before React 16, in the coordination phase, this is also called a Stack Reconciler because of the recursive traversal that is adopted. This approach has one characteristic: Begin once the task cannot be interrupted, so js will always occupy the main thread, always have to wait until after the completion of the whole Virtual DOM tree in computing to the executive power to the rendering engine, then this will lead to some user interaction, animation and so on task cannot be processed immediately, there will be caton, the influence of the user experience very much.

Presentation: amplification

The Fiber Reconciler proposed by React 16 is aimed at addressing the above issues. Fiber implements its own component call stack, which traverses the component tree as a linked list, breaking down a large task into smaller tasks that can be paused, continued, and dropped.

React Fiber The React Fiber update process is divided into two phases:

  • In the first stage, Fiber tree is generated and the node information to be updated is obtained. This step is a gradual process that can be interrupted.
  • In phase 2, nodes that need to be updated are updated in batches at a time. This process cannot be interrupted.

Phase 1 can be interrupted or restarted, and the lifecycle functions of this phase can be executed multiple times. Happened to developers in componentWillMount, componentWillReceviesProps, getDerivedStateFromProps (nextProps prevState) did some dangerous operation, such as sending an asynchronous request, This leads to bugs. React 16 deprecates the above three lifecycle functions because of this. Fiber is implemented in a similar way to the previous section on “Why Scrap some life cycles”.

Segmentfault.com/a/119000001…