在vue中
-
代码编译过程: template -> 通过compile部分 进行转换成 -> render()也就是[h("div",{props},children)]
-
在修改响应式变量时候。他会触发该变量的set方法 然后进行重新执行render函数
在React中
- 代码通过babel编译 拿到render() -> 通过React.createElement("div",{},children)
- 在修改响应式变量时候,必须手动调用this.setState() 当修改的值和原值一样的话。他内部也会重新调一次render() 这就造成了不必要的渲染
这个时候可以使用钩子函数 shouldComponetUdate(preState)
在内部 进行判断
{ if(preState.message===this.state.message){return false} }
也可以使用PureComponent
因为React 中他没有vue中的方式 对数据进行了数据劫持 所以必须通过setState来告知React数据已经发生了变化 其中setState方法是从Component方法中继承过来的
setState 使用
-
直接使用 在
this.SetState({ message:1 })
过程中 他在源码中其实就是使用了Object.Assign(this.state,newState) 在合适的时机下 调用render() -
函数方式使用
this.steState((state,props)=>{return {message:1,age:state.opo})
- 好处一 可以在回调函数中编写新的state逻辑
- 好处二 可以使用之前的state和props参数
- setState 函数处理中是一个异步调用
我们并不能在执行完setState之后立马拿到最新的state的结果
如果希望数据更新后立刻获取到最新的值。setState 会有第二个参数callback
this.setState({message:'修改'},()=>{return this.state.message})
setState 异步调用
在React 18 之前 有些操作是setState是个同步操作的 但是在React 18 之后 就会全部变成异步操作
可以使用 给setState 包裹在一个宏任务队列里 这样setState就会在浏览器执行宏任务队列时候来回调执行该函数 这就跟React事件执行没关系了 这样就会把setState变成一个同步操作
setTimeout(()=>{this.setState({message})},0)
原生DOM中监听 addEventListener
promise回调
但是在React18之后 把所有宏任务的回调函数 都会变成批量处理 异步操作
1.为什么setState 设置为异步操作
React核心成员(Redux的作者)Dan Abramov也有对应的回复 github.com/facebook/re…;
- 可以显著提升性能
- 如果每次调用setState都进行一次更新的话,那么意味着render函数会频繁调用 界面多次渲染 虚拟DOM将会做多次diff算法 浏览器多次回流与重制 这样效率会很低的
- 最好的办法就是获取到多个更新,之后进行批量更新
- 如果同步更新了state 但是还没有执行render函数 那么state和props将不能同步
- state和props不能保持一致性,将会导致页面渲染的值和state目前的值 不一致
- setState的批量处理
- 就是把setState放进一个队列(先进先出里面 然后会讲依次合并 其实内部是做了一个do while循环 等合并结束了 再统一执行render函数
如果要使用最新的state的话 可以用 this.steState((state,props)=>{return {message:1,age:state.opo})
这个参数state是最新的state值 但是在函数内部使用this.state.message
这个值还是更新之前
- 如果希望setState进行同步处理的话 使用 从react-dom包中获取到flushSync
flushSync在函数内部还是批处理
flushSync(()=>{this.setState({message:1})})