React中setState方法详解

Posted 热心的前端人员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React中setState方法详解相关的知识,希望对你有一定的参考价值。

一、为什么要使用 setState 方法,如何用?

         在 React 中,组件分为 有状态组件无状态组件,有状态组件就是能够定义 state 的组件,比如类组件,无状态组件反之,比如函数组件。state 就是用来描述事物在某时刻的数据,可以被改变,改变后与视图相映射,用来保存数据和响应视图。

        虽然状态可以改变,但不是响应式的,动态改变并没有与视图响应,想要改变并响应视图则需要 setState 修改并更新视图。

        使用方法:this.setState( 修改的数据 )

        setState并不会影响其他没有进行修改的数据,此方法是从Component中继承过来的

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

export default class App extends Component 
    // 定义 state
    state = 
        count: 0,
        list: [1, 2, 3],
        person: 
            name: 'jack',
            age: 18,
        ,
    
    changeCount = () => 
        // this.state.count++
        // 上面的写法并不能更新视图,想要双向更新只能利用 setState 方法
        this.setState(
            count: this.state.count,
        )
    
    changeList = () => 
        // 同理
        this.state.list.push('Hello React')
        this.setState(
            list: this.state.list,
        )
    
    changePerson = () => 
        this.state.person.name = 'ifer'
        this.state.person.age = 19
        this.setState(
            person: this.state.person,
        )
    
    render() 
        return (
            <div>
                <h3>count输出</h3>
                <p>this.state.count</p>
                <button onClick=this.changeCount>click</button>
                <hr />
                <h3>list输出</h3>
                <ul>
                    this.state.list.map((item, index) => (
                        <li key=index>item</li>
                    ))
                </ul>
                <button onClick=this.changeList>click</button>
                <hr />
                <h3>person输出</h3>
                <p>
                    this.state.person.name this.state.person.age
                </p>
                <button onClick=this.changePerson>click</button>
            </div>
        )
    


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

        状态有个特性是不可变性,就是不可以直接修改原数据,而是直接产生一个新的数据,通过 setState 方法把新的数据覆盖原有的数据,从而进行响应视图,这么做有利于性能优化和 SCU。

 二、setState 使用触发的钩子函数

  1. render() ———— 每次组件渲染都会触发

    注意:render()中不要调用 setState 方法,会发生死循环。
     
  2. componentDidUpdate() ———— 组件更新(完成DOM渲染)后触发

三、setState 是同步代码 

        虽说 setState 很多人说是异步的,但是它本身的执行过程和代码是同步的,只是它在合并数据与钩子函数的调用顺序在更新后无法拿到值,形成了 异步 ,我们可以通过第二个参数拿到更新后的结果。

changeText() 
  this.setState(
    age: 20
  , () => 
    console.log(this.state.age); // 文本已经被改变,得到的是20
  );

        也可以通过钩子函数获取修改后的值

componentDidUpdate() 
  console.log(this.state.age);

什么时候“同步”,什么时候“异步”?

  • 一般情况下(常见在生命周期或者是合成事件处理函数中),通过 setState() 方法来更新状态,表现是 异步 的。
     
    state =  count: 1 
    
    this.setState(
        count: this.state.count + 1,
    )
    
    console.log(this.state.count) // 1
    // 通过 DOM 不能立马获取更新后的值
  • 当执行到 setState 时,React 出于性能考虑,并不会立马执行修改 state ,而是先把当前更新对象以及后续的合并到一起,放在一个更新队列里进行合并操作,这期间并不会影响后续代码执行。且多次调用会合并,以最后一次渲染为主,以此来进行性能优化。
     
    this.setState(
        count: this.state.count + 1,
    )
    this.setState(
        count: this.state.count + 2,
    )
    this.setState(
        count: this.state.count + 3,
    )
    
    // 最后实现更新的是最后一个代码,前面的都会被覆盖

    如果想要实现一个一个实现,可以利用 setState 的第二个参数,第二个参数是一个回调函数,在更新完之后会执行

    // setState 有两个参数,第二个参数可以立即拿到更新后的值
    this.setState(, () => 
        console.log('这个回调函数会在状态更新后立即执行')
    )
    this.setState(() => (
    	count: this.state.count + 1
    ))
    // prevStart 是最近一次的更新的数据
    this.setState((prevStart) => (
    	count: prevStart.count + 2
    ))
    this.setState((prevStart) => (
    	count: prevStart.count + 3
    ))

    上面确实可以累加,把累加的结果渲染到页面上,但依然不能改变异步更新的表现形式

  • 如果在 setTimeout/setInterval 或者原生事件(比如点击事件等)的回调中,或者是在 setState 前面遇到 await 后续表现都为 同步 的。

       利用定时器
     
    import React,  Component  from 'react'
    
    export default class App extends Component 
        state = 
            count: 1,
        
        componentDidMount() 
            setTimeout(() => 
                this.setState(
                    count: this.state.count + 1,
                )
                console.log(this.state.count) // 2
            )
        
        render() 
            return <div>this.state.count</div>
        
    

     原生事件

    import React,  Component, createRef  from 'react'
    
    export default class App extends Component 
        state = 
            count: 1,
        
        countRef = createRef()
        componentDidMount() 
            this.countRef.current.onclick = () => 
                this.setState(
                    count: this.state.count + 1,
                )
                console.log(this.state.count) // 2
            
        
        render() 
            return (
                <div>
                    <h2>this.state.count</h2>
                    <button ref=this.countRef>点击</button>
                </div>
            )
        
    

    async写法

    import React,  Component  from 'react'
    
    export default class App extends Component 
        state = 
            count: 1,
        
        async componentDidMount() 
            await this.setState(
                count: this.state.count + 1,
            )
            console.log(this.state.count) // 2
        
        render() 
            return (
                <div>
                    <h2>this.state.count</h2>
                </div>
            )
        
    

以上是关于React中setState方法详解的主要内容,如果未能解决你的问题,请参考以下文章

setState详解与React性能优化

深入React技术栈之setState详解

React中的setState使用细节和原理解析

JS每日一题: 如何理解react中setState?

[转]React官方学习笔记

setState详解