[Front-end framework] react framework Chapter 5 reveals the principle of react

1. Description of setState()

Reasons to use setState

In development, we cannot update the interface directly by modifying the value of the state:
because after we modify the state, we hope that React will re-render the interface according to the latest State, but this.state modification React does not know the data There has been a change.

There is no setState method implemented in the component, why can it be called?
The reason is simple, the setState method is inherited from Component. I have found the corresponding source code, and you can see that in the source code, setState is placed on the prototype of Component

setState recommended syntax

  1. Recommendation: use setState((state, props) => {})syntax
  2. Parameter state: Indicates the latest state
  3. Parameter props: Indicates the latest props
//推荐语法
// 注意:这种语法是异步更新state的!
handleClick = ()=>{
    
    
    this.setState((state,props)=>{
    
    
        return{
    
    
            conut:state.conut +1
        }
    })
    console.log('count:', this.state.conut)///1
}

second parameter

  1. Scenario: Perform an action immediately after a state update (page finishes re-rendering)
  2. grammar:setState(updater[,callback])
handleClick = ()=>{
    
    
    this.setState(
        (state,props)=>{
    
    },
        ()=>{
    
    console.log('这个回调函数会在状态更新后立即执行')}
    )    
    
}
handleClick = ()=>{
    
    
    this.setState(
        (state,props)=>{
    
    },
        ()=>{
    
    document.title='更新state后的标题:'+this.state.count}
    )    
    
}

Basic usage of setState

Common usage of setState

Usage one:

Pass in an object directly in the setState function, and the passed object will be merged with the object of this.state, and the same property will be overwritten. After the modification is completed, wait for the task queue to batch
call the render function to update the page

export class App extends Component {
    
    
  constructor() {
    
    
    super()

    this.state = {
    
    
      name:"小莉"
    }
  }
  
  changeText() {
    
    
    this.setState({
    
    
      name:"猪"
    })
  }

  render() {
    
    
    const {
    
     name } = this.state
    return (
      <div>
        <h2>{
    
    name}</h2>
        <button onClick={
    
    () => {
    
    this.changeText()}}>点我</button>
      </div>
    )
  }
}

Usage two:

In the setState function, a callback function is passed in, and the callback function passed in is required to return an object, and React will internally merge the returned object with the state object

The benefits of usage two:

  1. In this callback function, the logic of modifying state data can be written, which has stronger cohesion
  2. The current callback function will pass in state and props by default, we can get it directly in the callback function, no need to get it through this.state or this.props
export class App extends Component {
    
    
  constructor() {
    
    
    super()

    this.state = {
    
    
      name:"小莉"
    }
  }
  
  changeText() {
    
    
    this.setState((state, props) => {
    
    
      // 可以直接在回调函数中获取state和props
      console.log(state, props);

      // 对数据进行操作的逻辑
      const name = state.name + "小莉"

      // 该回调函数返回一个对象
      return {
    
    
        name
      }
    })
  }

  render() {
    
    
    const {
    
     name } = this.state
    return (
      <div>
        <h2>{
    
    name}</h2>
        <button onClick={
    
    () => {
    
    this.changeText()}}>点我</button>
      </div>
    )
  }
}

setState is updated asynchronously

You can use the following code to check, after executing setState, we print the result of name immediately

export class App extends Component {
    
    
  constructor() {
    
    
    super()

    this.state = {
    
    
      name:"小莉"
    }
  }
  
  changeText() {
    
    
    // 用法一
    this.setState({
    
    
      name:"猪"
    })
    console.log(this.state.name) // 小莉
  }

  render() {
    
    
    const {
    
     name } = this.state
    return (
      <div>
        <h2>{
    
    name}</h2>
        <button onClick={
    
    () => {
    
    this.changeText()}}>点我</button>
      </div>
    )
  }
}

The printed result is "Xiaoli", which is not the modified result.
It can be seen that setState is an asynchronous operation, and we cannot get the latest state result immediately after executing setState

So why is setState designed to be asynchronous?

Two main reasons for designing to be asynchronous

1. setState is designed to be asynchronous, which can significantly improve performance:
we know that calling setState will cause the render function to be re-executed. If an update is performed every time setState is called, it means that the render function will be called frequently and the interface will be re-rendered. is very low. The best way should be to obtain multiple updates, and then perform batch updates (or unified updates). The same is true in React. In a period of time, multiple updates will be obtained, and then multiple updates will be put into a task queue, and then the task queue will be batch-processed. If there are other updates that are not in the current time period, batch them in the task queue for the next time period (or other time period)

2. If the state is updated synchronously, but the render function has not been executed, then the state and props cannot be kept in sync:
state and props cannot be consistent, which will cause many problems in development.

2. The transformation process of JSX syntax

  1. JSX is just syntactic sugar for the createElement() method (simplified syntax)
  2. The JSX syntax @babel/preset-react plugin is compiled into the createElen() method
  3. React element: is an object that describes what you want to see on the screen

Conversion process:

JSX语法 --> createElement() --> React元素

3. Component update mechanism

  1. setState()Two functions: modify state and update components (UI)
  2. Process: When the parent component re-renders, the child components will also be re-rendered, but only 当前组件子树(the current component and all its child components)

4. Component performance optimization

reduce state

  1. 减轻state: Only store data related to component rendering (for example: count / list data / loading, etc.)
  2. Note: Do not put data that does not need to be rendered in the state, such as timer id, etc.
  3. For this kind of data that needs to be used in multiple methods, it should be placed in this
class Hello extends React.Component{
    
    
    componentDidMount(){
    
    
        // timerId存储到this中,而不是state中
        this.timerId = setInterval(()=>{
    
    },200)
    }
    componentWillUnmount(){
    
    
        clearInterval(this.timerId)
    }
    render(){
    
    ...}
}

Avoid unnecessary re-renders

  1. Component update mechanism: the update of the parent component will cause its child components to be updated as well. This idea is very clear
  2. Problem: Subcomponents are also updated when there is no change
  3. How to avoid unnecessary re-rendering?
    Solution: 使用钩子函数shouldComponentUpdate(nextProps,nextState)
    Function: Determine whether the component is re-rendered by the return value, returning true means re-rendering, false means not re-rendering
    Trigger timing: hook function in the update phase, execution before component re-rendering ( shouldComponentUpdate --> render )
class Hello extends React.Component{
    
    
    shouldComponentUpdate(){
    
    
        // 根据条件是否重新渲染组件
        return false
    }
    render(){
    
    ...}

}

random number case

class App extends React.Component{
    
    
    // 因为两次生成的随机数可能相同,如果相同中,此时,不需要重新渲染
    shouldComponentUpdate(nextProps,nextState){
    
    
    	//return nextState.number!==this.state.number 和以下代码等同
        if(nextState.number===this.state.number){
    
    
            return false
        }
        return true
    }
    render(){
    
    ...}
}

class NumberBox extends React.Component{
    
    
    shouldComponentUpdate(nextProps){
    
    
        // 如果前后两次的number值相同,就返回false,不更新组件
        //return nextProps.number!==this.props.number 和以下代码等同
        if(nextProps.number===this.props.number){
    
    
            return false
        }
        return true

    }
    render(){
    
    ...}
}

Code:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

class App extends React.Component{
    
    
    state = {
    
    
        number:0
    }

    handleClick = ()=> {
    
    
        this.setState(()=>{
    
    
            return {
    
    
                number:Math.floor(Math.random() *3)
            }
        })
    }

    // 因为两次生成的随机数可能相同,如果相同中,此时,不需要重新渲染
    shouldComponentUpdate(nextProps,nextState){
    
    
        console.log('最新状态:',nextState,",当前状态:",this.state)
        if(nextState.number===this.state.number){
    
    
            return false
        }
        return true
    }

    render(){
    
    
        return(
            <div>
                <h1>随机数:{
    
    this.state.number}</h1>
                <button onClick={
    
    this.handleClick}>重新生成</button>
            </div>
        )
    }
}

class NumberBox extends React.Component{
    
    
    shouldComponentUpdate(nextProps){
    
    
        console.log('最新props:',nextProps,",当前props:",this.props)
        // 如果前后两次的number值相同,就返回false,不更新组件
        if(nextProps.number===this.props.number){
    
    
            return false
        }
        return true

    }
    render(){
    
    
        console.log('子组件中的render')
        return <h1>随机数:{
    
    this.props.number}</h1>
    }
}


ReactDOM.render(<App />,document.getElementById('root'))

pure component

  1. Pure Components: React.PureComponentFunctionally similar to React.Component
  2. Difference: The shouldComponentUpdate hook function is automatically implemented inside PureComponent, no manual comparison is required
  3. 对比Principle: The pure component internally determines whether to re-render the component through the values ​​of props and state before and after
class Hello extends React.PureComponent{
    
    
    render(){
    
    
        return <h1>纯组件</h1>
    }
}

Code:

import React from 'react'
import ReactDOM from 'react-dom'


class App extends React.PureComponent{
    
    
    state = {
    
    
        number:0
    }

    handleClick = ()=> {
    
    
        this.setState(()=>{
    
    
            return {
    
    
                number:Math.floor(Math.random() *3)
            }
        })
    }

    render(){
    
    
        // console.log('父组件中的render')
        return(
            <div>
                <NumberBox number={
    
    this.state.number}/>
                <h1>随机数:{
    
    this.state.number}</h1>
                <button onClick={
    
    this.handleClick}>重新生成</button>
            </div>
        )
    }
}

class NumberBox extends React.PureComponent{
    
    
    
    render(){
    
    
        console.log('子组件中的render')
        return <h1>随机数:{
    
    this.props.number}</h1>
    }
}


ReactDOM.render(<App />,document.getElementById('root'))


  1. Explanation: The comparison inside the pure component is shallow compare(shallow comparison)
  2. For value types, compare whether the two values ​​are the same (direct assignment is enough)
let number =0
let newNumber = number
newNumber = 2
console.log(number===newNumber) //false

state = {
    
    number:0}
    setState({
    
    number:Math.floor(random() *3)})
    }
    // PureComponent内部对比
    最新的state.number === 上一次的state.number //false,则重新渲染组件

  1. For 引用类型: only compare whether the reference (address) of the object is the same
  2. Notice:state或props中属性值为引用类型时,应该创建新数据,不要直接修改原数据
const obj={
    
    number:0}
const newObj = obj
newObj.number = 2
console.log(newObj===obj)  //true
// 正确!创建新数据
    const newObj = {
    
    ...state.obj,number:2}
    setState({
    
    obj:newObj})

    // 正确!创建新数据
    // 不要用数组的push / unshift等直接修改当前数组的方法
    // 而应该用concat 或 slice 等这些返回新数组的方法
    this.setState({
    
    
        list:[...this.state.list,{
    
    新数组}]
    })

Virtual DOM and Diff algorithm

  1. The idea of ​​React updating the view is: re-render the view whenever the state changes
  2. Features: very clear thinking
  3. Question: When only one DOM element in the component needs to be updated, do you have to re-render the content of the entire component to the page?不是
  4. Ideal state: 部分更新, only update the changed places
  5. Question: How does React do partial updates?虚拟DOM配合Diff算法
  6. Virtual DOM (Virtual DOM) is a JS object used to describe the HTML structure content we want to see in the page.
  7. Virtual DOM: It is essentially a JS object used to describe the content (UI) you want to see on the screen. There
    is a one-to-one correspondence between the virtual DOM object and the HTML structure

Implementation process


  1. When the page is rendered for the first time, React will create a virtual DOM object (tree) process according to the initial state (Model) : 1 JSX + state => 2 virtual DOM tree (JS object) => 3 HTML seen in the browser structure content
  2. Generate real DOM based on virtual DOM and render it into the page
  3. When the data changes (setState()), create a new virtual DOM object (tree) based on the new data
  4. Compared with the virtual DOM object obtained last time, use the Diff algorithm (find the difference) to get the content that needs to be updated
  5. In the end, React only updates (patch) the changed content to the DOM and re-renders the page

insert image description here

insert image description here

Guess you like

Origin blog.csdn.net/qiqizgl777/article/details/129390628