深入认识 React 的 setState

  • 组件为了能够维护自身的状态,设置了state
  • 为了能够让React跟踪到状态的变化,规定只能通过setState更新状态

可能异步

setState 的调用方式相当于 Object.assign(之前的state,新的state)

然而,其实 setState 改变数据这个行为,有时候可能是异步的,也就是说,如果要立即获取改变后的状态,可能做不到

如下的代码的大致过程:

  1. state 中声明了一个 n
  2. html 中的 button 注册了一个点击事件
  3. 点击后,让 n + 1
  4. 立即打印 n

无论点击多少次,打印的始终是上一次 n 的值(不同步)

export default class Test extends Component {
  state = {
    n: 0
  }
  handleClick=()=>{
    this.setState({
      n:this.state.n + 1
    })

    console.log(this.state.n)  // 上面调用了 setState 后,立即打印 n : 依然等于 0
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>{this.state.n}</h1>
        <button onClick={this.handleClick}>add</button>
      </div>
    )
  }
}

原因推测

问题的根源,因为还没读过源码,暂且讲不清楚

不过根据下面的代码,可以推测一二:

  • constructor中添加了一定时器
  • 通过定时器回调函数改变状态, n + 1
  • 立即打印改变后的状态

这时,每次都是打印改变后的状态 n(同步)

export default class Test extends Component {
  state = {
    n: 0
  }

  constructor(props){
    super(props)
    setInterval(()=>{
      this.setState({
        n:this.state.n + 1
      })

      console.log(this.state.n)
    },1000)
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>{this.state.n}</h1>
      </div>
    )
  }
}

两相比较,得出初步结论: 在HTML上使用的处理函数调用的,是异步的;其他都是同步的

如何立即访问更新后的状态

这里说的只是html处理函数调用的 setState(其他的调用方式都是同步改变的)

使用 setState 的第二个参数

setState 方法的第二个参数是一个回调函数,该函数会在所有异步改变状态的 setState 执行完之后被调用

如下的情况(例子仅仅说明问题,没有实际意义):

export default class Test extends Component {
  state = {
    n: 0
  }
  handleClick=()=>{
    this.setState({
      n:this.state.n + 1
    },()=>{
      console.log('n: ',this.state.n)
    })
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>{this.state.n}</h1>
        <button onClick={this.handleClick}>add</button>
      </div>
    )
  }
}

回调函数中打印的this.state.n是改变后的状态数据

setState 直接传递一个函数

当需要连续改变多次状态,并且使用多次改变状态之后的值时,如果使用上面的方法会造成嵌套,而且导致组件渲染多次,不太好

可以给 setState 传递一个函数(同样的,例子仅仅说明问题,没有实际意义):

  1. 点击 button 后,连续三次修改状态
  2. 函数的参数 cur是当前状态,返回值是一个对象,与之前的状态 Object.assign
  3. 点击一次,实现了 n + 3
export default class Test extends Component {
  state = {
    n: 0
  }
  handleClick = () => {
    this.setState(cur => ({
      n: cur.n + 1
    }))
    this.setState(cur => ({
      n: cur.n + 1
    }))
    this.setState(cur => ({
      n: cur.n + 1
    }))
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>{this.state.n}</h1>
        <button onClick={this.handleClick}>add</button>
      </div>
    )
  }
}

结论

  • setState 状态是不可信任的,不要使用一般方式立即访问
  • HTML 上的处理函数调用的,比如: onClick onMouseEnter onMouseDown 等等,都是异步;其他方式是同步的
  • 可以给 setState 传递第二个参数,立即获取改变后的状态
  • 连续改变状态时,传递一个函数,函数参数为当前状态,返回值是将要混合的对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值