Core concepts of React

Keywords: Javascript React

Core concept of React (2)

 

1. Component introduction and props

 

1.1 component classification

 
Component, conceptually similar to JavaScript functions. It accepts any input parameter (i.e. "props") and returns the React element used to describe the content of the page presentation( Quoted from: Components & props )

 
Components are divided into class components and function components. Simple examples of the two components are given below:

// Function component
function FunctionComponent(name, address) {
  return `${name}stay ${address}Read!`;
}

// class component
class ClassComponent extends React.Component {
  render() {
    return <h1>Zhang San is studying in Beijing!</h1>;
  }
}

 

1.2 component rendering

function FunctionComponent(props) {
  const { name, address } = props;
  return `${name}stay ${address}Read!`;
}

const element = <FunctionComponent name="Zhang San" address="Beijing" />

ReactDOM.render(
  element,
  document.getElementById('root') // <div id="root" />
);

 
Let's briefly analyze the execution process:

 
First, element is JSX syntax. According to the previous section, the last element should be as follows:

const element = {
  type: 'div',
  props: {
    id: 'root',
    children: {
      type: 'h1',
      props: {
        name: 'Zhang San',
        address: "Beijing",
        children: 'Zhang San studies in Beijing 1',
      },
    }
  }
};

 
As can be seen from line 6 of the element above, although we define a component, in fact, after the conversion between Babel and React.createElement(), we get the React element used to describe the display content of the page.

 
Secondly, pass this element into ReactDOM.render() as the first parameter, and pass in the DOM node to be mounted as the second parameter to render the element as a DOM node.

 
Note: the component name must begin with a capital letter.

 

1.3 combined components

 
A component can reference other components in its output.

// Parent and Child are components
function Parent() {
  return (
    <div>
      <Child />
    </div>
  );
}

 

1.4 extraction components

 
Split components into smaller components.

 
When do I need to consider splitting components?

 
If a part of the UI is used many times (Button, Panel, Avatar), or the component itself is complex enough (App, FeedStory, Comment), it is a candidate for reusable components.

 

1.5 read only of props

 
Whether you use a function component or a class component, you must not modify your props. This is the rule and must be observed!

 

2.State

 
Before hooks appeared, only the class component had the state function. For hooks (special for function components), a special chapter will follow. Now we mainly use this.setState() and this.state of the class component to explain:

import React from 'react';

class ClassComp extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      count: 0,
    }
  }
  increase = () => {
    const { count } = this.state;
    this.setState({ count: count + 1 });
  }

  render () {
    const { count } = this.state;
    return (
      <>
        <div>{count}</div>
        <button onClick={this.increase}>click</button>
      </>
    )
  }
} 

export default ClassComp;

 
The above code is a simple example of increasing the count.

 

2.1 do not modify the State directly

 

this.state.count = 100;

This modification method is wrong. react compares the old and new states through Object.is(). If it is modified directly, Object.is() will judge that the count s in the old and new states are equal, so that the components will not be re rendered.

 

2.2 State updates may be asynchronous

 
For performance reasons, React may combine multiple setState() calls into one call.

increase = () => {
  const { count } = this.state;
  this.setState({ count: count + 1 });
  this.setState({ count: count + 1 });
  this.setState({ count: count + 1 });
}

 
After this click, does the count become 3?

 
Of course, if I ask this, many students will find that this is a pit. Yes, the correct answer is: 1.

 
this.setState() has been called three times. Why is this? This goes back to what we said at the beginning of this section: for performance reasons, React may combine multiple setState() calls into one call.

 
After clicking, you call three times setState(), but in fact, due to merge calls, the state of three consecutive calls is actually 0, so every increment is 0 + 1, and naturally the final result is 1..

 
Can't we rely on their values to update the next state?

 
So what if, in some cases, I have to rely on the previous state? There is also a solution. Consider the following code:

increase = () => {
  const { count } = this.state;
  this.setState(state => ({ // At this point, state.count = 0
    count: state.count + 1,
  }));
  this.setState(state => ({ // At this point, state.count = 1
    count: state.count + 1,
  }));
  this.setState(state => ({ // At this time, state.count = 2
    count: state.count + 1,
  }));
}

 
At this time, you will find that each time you click the Add button, the value increases by 3. Why?

 
This is because when we call this.setState(), we no longer pass in an object, but a function. The parameters of this function are guaranteed to be the latest state. Therefore, each time we increase, we use the value in the latest state as the addend.

 
Note 1: there are actually two parameters of this.setState() function. The first parameter is the latest state and the second parameter is the latest props

 
Note 2: other ways to obtain the changed state value in time (synchronization)

 
1. By passing in the second parameter (function) in setState, setState is synchronous

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

 
2. setState in setTimeout is synchronous

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

 
3. For self-defined DOM events, setState is synchronous

componentDidMount = () => {
  document.body.addEventListener('click', this.handleClick);
}

// Execute on component destruction
componentWillUnmount = () => {
  // That is, destroy the custom DOM event
  document.body.removeEventListener('click', this.handleClick);
}

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

 
Remember to destroy the custom DOM events here, including the setTimeout used above. You also need to execute clearTimeout in componentWillUnmount.

 

2.3 State updates will be merged

 
When you call setState(), React will merge the objects you provide into the current state( When a function is passed in, it will not be merged, as in the example in 2.2)

 
Consider the following code:

// Omit some codes
constructor (props) {
  super(props);
  this.state = {
    count: 0,
    total: 100,
  }
}

increase = () => {
  const { count } = this.state;
  this.setState({
    count: count + 1,
  });
}

The total value in this.state is 100. In the increase function, we increase the value of count. At this time, React will completely retain this.state.total and completely replace this.state.count.

 
Note: the merge here is a shallow merge, so even if the value in this.state is a reference type, the address is actually replaced during replacement.

 

3. Data flow moves downward

 
React data is top-down or unidirectional. Any state always belongs to a specific component, and any data or UI derived from this state can only affect the components "below" them in the tree.

 
Neither parent component nor child component can know whether a component is stateful or stateless, and they don't care whether it is a function component or a class component.

 
The component can choose to pass its state down to its sub components as props:

<h1>{this.state.count}</h1>

 
The same applies to custom components:

<selfComp count={this.state.count} />

 
Each component is truly independent (quoted from: React data flows downward )

Posted by Zepo. on Wed, 01 Sep 2021 16:13:44 -0700