React的setState

什么是setState

setState() 将对组件 state 的更新排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式

   setState() 并不总是立即更新组件。它会批量推迟更新。这使得在调用 setState() 后立即读取 this.state 成为了隐患。为了消除隐患,请使用 componentDidUpdate 或者 setState 的回调函数(setState(updater, callback)),这两种方式都可以保证在应用更新后触发
除非 shouldComponentUpdate() 返回 false,否则 setState() 将始终执行重新渲染操作。如果可变对象被使用,且无法在 shouldComponentUpdate() 中实现条件渲染,那么仅在新旧状态不一致调用 setState()可以避免不必要的重新渲染

是干嘛的

用来修改页面的数据的

怎么使用

setState(updater, [callback])

this.setState({
  count: this.state.count + 1
})

this.setState({
  count: this.state.count + 1
}, () => {
  vue的 $nextTick
  console.log('count by callback', this.state.count)  // 回调
})
  • 通过setState去修改message,是不会对其他 state 中的数据产生影响的

  • 源码中其实是有对 原对象 和 新对象 进行合并的

 return Object.assign({}, prevState, parialState);

  • 当我们的多次调用了 setState只会生效最后一次state

为什么不能这么那么使用

this.state.count + +

不能修改state自身,必须通过setState()

React 不能直接修改 state 自身的原因是为了确保数据的一致性和可预测性,以及配合 React 的更新机制进行正确的 DOM 更新。

  1. 一致性和可预测性

    • 直接修改 state 自身可能会导致数据变化的不可控和不一致性。React 鼓励使用不可变数据(immutable data)的概念,通过创建新的数据副本来表示数据的变化。
    • 不可变数据可以让我们更容易跟踪数据的改变,避免出现意外的数据变化,从而提高代码的可维护性和可预测性。
  2. 配合 React 的更新机制

    • 直接修改 state 自身可能会绕过 React 的更新机制,导致视图与状态不同步。
    • 通过 setState 方法来修改 state,可以触发 React 的更新流程,确保视图能够及时地根据最新的状态进行更新。

因此,使用 setState 方法来修改 state 是 React 设计的一部分,它强调了数据的不可变性和通过统一的方式来更新状态,以确保应用的稳定性和可维护性。

当你调用 setState 方法时,React 会在遵循特定的更新流程后,根据新的状态重新渲染组件,从而使得视图与状态保持同步。

总的来说,React 不能直接修改 state 自身是为了保证数据的一致性、可预测性,并配合 React 的更新机制进行正确的 DOM 更新。

setState特性


      不可变值
      可能是异步更新
       可能会被合并

1. 不可变值

React 不能直接修改 state 自身的原因是为了确保数据的一致性和可预测性,以及配合 React 的更新机制进行正确的 DOM 更新。

  1. 一致性和可预测性

    • 直接修改 state 自身可能会导致数据变化的不可控和不一致性。React 鼓励使用不可变数据(immutable data)的概念,通过创建新的数据副本来表示数据的变化。
    • 不可变数据可以让我们更容易跟踪数据的改变,避免出现意外的数据变化,从而提高代码的可维护性和可预测性。
  2. 配合 React 的更新机制

    • 直接修改 state 自身可能会绕过 React 的更新机制,导致视图与状态不同步。
    • 通过 setState 方法来修改 state,可以触发 React 的更新流程,确保视图能够及时地根据最新的状态进行更新。

因此,使用  setState方法来修改 state 是 React 设计的一部分,它强调了数据的不可变性和通过统一的方式来更新状态,以确保应用的稳定性和可维护性。

当调用 setState 方法时,React 会在遵循特定的更新流程后,根据新的状态重新渲染组件,从而使得视图与状态保持同步。

总的来说,React 不能直接修改 state 自身是为了保证数据的一致性、可预测性,并配合 React 的更新机制进行正确的 DOM 更新。

this.setState({
  list1: this.state.list1.concat(100), // 追加
  list2: [...this.state.list2, 100], // 追加
  list3: this.state.list3.slice(0, 3) // 截取
  list4: this.state.list4.filter(item => item>100), // 筛选
  list5: list5Copy // 其他操作
})
注意:不能直接对 this.state.list进行push pop splice等,这样违反不可变

不可变值-对象
this.setState({
  obj1: Obiect.assign({}, this.state.obj1, {a: 100}),
  obj2: {...this.state.obj2, a: 100}
})
  • 源码中对 原对象 和 新对象 进行合并的

2. 同步异步
其实可以分成两种情况:
在   组件生命周期   或   React合成事件   中, setState是异步的

this.setState({
  count: this.state.count + 1
})
它是一个异步的操作
在上下文,拿不到修改后的值
console.log('count', this.state.count) // 这样是拿不到这个this.state.count修改后的值的

必须在后面加一个箭头函数才能拿到
this.setState({
  count: this.state.count + 1
}, () => {
  vue的 $nextTick
  console.log('count by callback', this.state.count)  // 回调
})


在   setTimeou     或    原生DOM事件    中, setState是同步的

验证一: 在setTimeout中的更新
changeText() {
  setTimeout(() => {
    this.setState({ message: '你好' })
    console.log(this.state.message)  // -> 你好
  }, 0)
}

验证二:在原生DOM事件 -> 同步更新
componentDidMount() {
  document.getElementById('btn),addEventListener('click', e => {
    this.setState({ message: '你好' })
    console.log(this.state.message)
  })
}

React18之后,所有操作都是异步的了,如果想让setState同步处理任务,需要加一个flushSync,就如vue中的async await

flushSync(() => {
  this.setState({ message: "你好啊" })
})
// 这里获取就是同步的
console.log(this.state.message) // 你好啊

2. setState的基本过程

setState的调用会引起React的更新生命周期的4个函数执行:

        shouldComponentUpdate       componentWillUpdate    render componentDidUpdate

        当shouldComponentUpdate执行时,返回true,进行下一步,this.state没有被更新
返回false,停止,更新this.state

         当componentWillUpdate被调用时,this.state也没有被更新,直到render被调用时候,this.state才被更新。

总之,直到下一次render函数调用(或者下一次shouldComponentUpdate返回false时)才能得到更新后的this.state

setState更新原理

  1. 触发状态更新

    • 当调用 setState(newState, callback) 时,React 会将新的状态 newState 存储在内部的更新队列中,并标记组件为“脏”(dirty)。
  2. 批量更新

    • 如果在一个事件处理函数中多次调用 setState,React 会对这些状态更新进行合并,只执行一次更新操作,以提高性能。
  3. 调度更新

    • React 使用异步更新机制来调度状态更新,它会利用事务机制、批量更新等技术来确保更新的顺序和性能。
  4. 执行 render

    • 在下一个事件循环中,React 根据更新队列中的状态变化,重新调用组件的 render 方法生成虚拟 DOM。
  5. 比较与更新

    • React 使用虚拟 DOM 的 diff 算法比较新旧虚拟 DOM 的差异,然后只更新有变化的部分到实际 DOM 中。
  6. 生命周期方法调用

    • 更新完成后,React 会调用相应的生命周期方法(如 componentDidUpdate),让开发者有机会做一些额外的操作。

源码

1在class中能够使用setState的原因,如下面源码中的,继承了component

Component.prototype.setState = function(partialState, callback) {
    invariant(
        typeof partialState === 'object' ||
          typeof partialState === '' ||
          partialState == null,
        'setState(...): takes an object of state variables to update or a' +
        'function which returns on object of state variables.',
    );
    this.updater.enqueueSetState(this, partialState, callback, 'setState');
}

2setState同步异步的原因

const classCompenentUpdater = {
    isMounted,
    enqueueSetState(inst, payload, callback){
        const fiber = getInstance(inst);
        const currentTime = requestCurrentTimeForUpdate();
        const suspenseConfig = requestCurrentSuspenseConfig();
        const expirationTime = computeExpirationForFiber(
            currentTime,
            fiber,
            suspenseConfig,
        );
        
        const update = createUpdate(expirationTime, suspenseConfig);
        update.payload = payload;
        if (callback !==undefined && callback !==null) {
            if (__DEV__) {
                warnOnInvalidCallback(callback, 'setState');
            }
            update.callback = callback;
        }
        
        enqueueUpdate(fiber, update);
        scheduleWork(fiber, expirationTime);
    },
    enqueueReplaceState(inst, payload, callback){...
    },
    enqueueForceUpdate(inst, callback){...
    }
}

函数组件和class组件的使用区别


深入浅出 setState 原理篇                             https://zhuanlan.zhihu.com/p/470429343
React学习-setState的执行机制                         https://www.cnblogs.com/zhilili/p/16067832.html
从 setState 聊到 React 性能优化              https://baijiahao.baidu.com/sid=1714389526829756241&wfr=spider&for=pc
12_React扩展(setState的两种写法、lazyLoad、Hooks等)  https://blog.csdn.net/weixin_42152058/article/details/130619775
React中的setState使用细节和原理解析                   https://blog.csdn.net/m0_71485750/article/details/126649380
 

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值