2022 is coming, the front end development is very rapid, now the front end is no longer writing simple pages, with the Web big front end, engineering is becoming more and more hot, there are also many frameworks. Many companies are not only using a single framework, as the front end development of the two most popular frameworks in the country, are necessary to master. Therefore, I decided to learn React at the end of this year when the epidemic was raging, so as to gain more competitiveness in my future job search.

Learning stage, if there is something wrong, welcome to leave a message in the comment area, I timely correction

This article has been serialized, other chapters portal ⬇️

Chapter 1 – Understanding JSX syntax

Chapter 2 – Function components and Class components

Chapter 4 – Event Handling

Chapter 5 -Ref and Refs

Chapter 6 – Life Cycle

Chapter 7 – Communicating Context across Components

Chapter 8 -React Hooks

Props and State

React uses props to receive data, and state maintains its own data. The props property is read-only and cannot be modified. If the data is modified, we can only modify the state of the parent component.

Props

💡 props can accept multiple types of data, even one component, which is very flexible, we can pass any data through props

Passing ordinary data

import {Component} from 'react'
import ReactDOM from 'react-dom'

class Demo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      date: '2022-01-14'}}render() {
    return(
      <Date date={this.state.date} />)}}function Date(props) {
  console.log(props)
  return (
    <h1>{props.date}</h1>
  )
}
ReactDOM.render(<Demo />.document.querySelector('#root'))
Copy the code

Let’s print props so we can see what it looks like, okay

Pass a piece of structure

import {Component} from 'react'
import ReactDOM from 'react-dom'

class Demo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      date: '2022-01-14'}}render() {
  const element = <h1>{this.state.date}</h1>
    return(
      <Date date={element} />)}}function Date(props) {
  console.log(props)
  return (
    <div>
      {props.date}
    </div>
  )
}
ReactDOM.render(<Demo />.document.querySelector('#root'))
Copy the code

We’ve changed the code here so that passing a structure through props seems to work

The date attribute (props) is a REACT DOM element. The date attribute (props) also has a children attribute (props), which contains the date of the parent component. This means that anything written in the middle automatically adds an attribute to props.

The children property of props

Next, try passing a structure or text between components

import {Component} from 'react'
import ReactDOM from 'react-dom'

class Demo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      date: '2022-01-14'.name: 'Ming'}}render() {
    return(
      <Date date={this.state.date}>
        {this.state.name}
      </Date>)}}function Date(props) {
  console.log(props)
  return (
    <div>
      <h1>{props.date}</h1>
    </div>
  )
}
ReactDOM.render(<Demo />.document.querySelector('#root'))
Copy the code

If we pass a structure or a component, then it’s an object. If we pass multiple structures or components, So its value is an array

The code is omitted, and the result of the console is directly captured:

If children were an array, we could iterate over all the children

State

💡 state provides the data used to maintain components, similar to the data function in VUE

Only class components have state. It provides the data that the component initializes. We can use this.state. Get the property name. So let’s see how we can modify the state data. Ok

React provides the only way to change state: setState()

For example, a small requirement, implement a counter function, click a button can add or subtract data

class Demo extends React.Component {
  constructor() {
    super(a)this.state = {
      counter: 0
    }
  }
  handelClick = (num) = > {
    this.setState({
      counter: this.state.counter + num
    })
  }
  render() {
    return(
      <div>
        <h2>Current count: {this.state.counter}</h2>
        <button onClick={()= > {this.handelClick(1)}}>+ 1</button>
        <button onClick={()= > {this.handelClick(-1)}}>- 1</button>
      </div>
    )
  }
}
ReactDOM.render(<Demo/>.document.querySelector('#app'))
Copy the code

So let me write it this way for the moment, because we’re dealing with this problem, and we’ll talk about it, and you can see that we’ve successfully modified the data using the setState method

SetState use

In React, the setState method is the only way to modify data. It is a callback function that takes an object as an argument or a callback function as an argument. 👉 about setState

The object parameters

💡 Problem: When we call setState and print the data immediately, it will not display the updated data, but the last one, and multiple setStates will be merged into one, and the later one will overwrite the previous one, as shown in the figure below

add = () = > {
    const { count } = this.state
    this.setState({
      count: count + 1
    })
    this.setState({
      count: count + 2
    })
    this.setState({
      count: count + 1
    })
    console.log(count)
  }
Copy the code

React will put the object parameters received by setState into an update queue, extract and merge all the objects together, and then trigger component updates. Therefore, multiple calls to setState will only trigger one re-render, since DOM updates are expensive

The callback parameter

💡 think: If we need to call multiple times and the data depends on the last result, is there a way to solve this problem? – In addition to object arguments, setState can also receive a callback argument, which takes a single argument that is the result of the last execution

add = () = > {
    const { count } = this.state
    this.setState((pre) = > {
      return {
        count: pre.count + 1}})this.setState((pre) = > {
      return {
        count: pre.count + 1}})this.setState((pre) = > {
      return {
        count: pre.count + 1}})console.log(count)
  }
Copy the code

Note that both object and function callbacks retrieve the data immediately after the setState call, so we need to retrieve the data after the component is updated, not immediately

SetState can take two functions as arguments, and the second function argument will wait for setState to execute before executing, so we can also fetch data in the second callback argument

SetState Synchronous or asynchronous

Conclusion 💡 : SetState is synchronous and behaves asynchronously due to React optimizations. SetState only behaves asynchronously in React raised events (such as onClick) and hook functions. This is synchronized in both native events (select DOM listener addEventListener) and setTimeout

👉 about setState synchronization asynchronous official website

React Event Handling

class Demo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      date: '2022-01-14'.name: 'Ming'.count: 0
    }
  }
  handleClick = () = > {
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count, 'First log')
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count, Log the second time.)
    setTimeout(() = > {
      console.log(this.state.count, Log the third time)
      this.setState({
        count: this.state.count + 1
      })
      console.log(this.state.count, 'Fourth log')
      this.setState({
        count: this.state.count + 1
      })
      console.log(this.state.count, 'Fifth log')})}render() {
    return(
      <div>
        <h1>Display current count: {this.state.count}</h1>
        <button onClick={this.handleClick}>button</button>
      </div>)}}Copy the code

We can see that the second log is printed immediately after the setState adjustment, but the initial value is still obtained. This also shows that multiple calls to React will be merged into a queue. Instead of updating the state immediately, it will update the state once, which behaves like async. And then after the third log, it’s already updating state immediately, which means it’s synchronized in setTimeout.

React hook function

componentDidMount = () = > {
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count, 'First log')
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count, Log the second time.)
    setTimeout(() = > {
      console.log(this.state.count, Log the third time)
      this.setState({
        count: this.state.count + 1
      })
      console.log(this.state.count, 'Fourth log')
      this.setState({
        count: this.state.count + 1
      })
      console.log(this.state.count, 'Fifth log')})}Copy the code

We changed the handleClick function to React lifecycle hook function componentDidMount. The printable result is the same as in the event handler.

Why doesn’t React update this.state synchronously?

React queues setState to be executed at once, thus avoiding the problem of components being rendered multiple times. If not, the performance overhead and experience would be bad. An update only needs to be re-rendered once. There is no need to re-render multiple times to cause a redraw

SetState Immutable power

We know that in JS, the simple type of data is directly occupied by the memory, and the complex type of data is only a reference, when we modify the simple type of data, is directly can be modified out. When we modify a complex type of data, such as obj.name = ‘xiaoming’, its reference address is not changed, it still points to the same memory space

export default class Index extends Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [{name: 'Ming'.id: 1
        },
        {
          name: 'little red'.id: 2}}}]shouldComponentUpdate(nextProps, nextState) {
    console.log(nextState)
    if(this.state.list ! == nextState.list) {return true
    }
    return false
  }
  addName = () = > {
    const obj = {name: 'xiao gang'.id: 3}
    this.state.list.push(obj)
    this.setState({
      list: this.state.list
    })
  }
  render() {
    console.log('Render function executed');
    return (
      <div>
        <ul>
          {
            this.state.list.map((item) => {
              return <li key={item.id}>{item.name}</li>})}</ul>
        <button onClick={this.addName}>button</button>
      </div>)}}Copy the code

For example, if we have a small requirement, click on the button to add a new piece of data to the array, and in the shouldComponentUpdate hook function, we should update the component by checking whether the list changes. If we are pushing an object directly into the list, we know that the array is a reference type. The referenced address does not change and does not change before and after state, resulting in return false and the component does not update. But when you print nextState, it’s already added, and the component doesn’t update no matter how many times you click it, because the reference address never changes

Let’s modify the code:

addName = () = > {
    const arr = [...this.state.list]
    arr.push({
      name: 'xiao gang'.id: 3
    })
    this.setState({
      list: arr
    })
  }
Copy the code

Using the es6 extension operator, we extend the array to a new array, not the original reference address, but a new array of reference addresses. After we add the data and reset the list value, we can see that the page is updated and re-rendered.