今天在码代码时遇到了一点问题,其实之前应该也是遇到过很多次的,不过当时很少用console
来实时检测自己的代码,一直没发现而已。
言归正传——
我在input组件上添加了一个onChange
事件来实时更新输入框的值textContent
,并通过console
输出显示,代码提炼如下:
import React from 'react';
class Demo extends React.Component{
state = {
textContent: '',
};
getText= (event) => {
this.setState({
textContent : event.target.value,
})
console.log(this.state.textContent);
}
render(){
return(
<div>
<input
style={{ width: 200}}
placeholder="XXXXXX"
value={this.state.textContent}
onChange={this.getText}
/>
</div>
)
}
}
结果问题出现了,每次打印的textContent
都是我上一次输入的内容,相当于滞后了一拍,并未达到实时更新的效果。
比如当我输入0,打印出的为空,因为我并未赋初始值,当我继续输入1时,才会出现我上次输入的0。
明明setState
已经执行完毕了呀,组件的state
应该已经被更新了,为什么还会console
出上一轮的值呢。
好奇心旺盛的我立刻去查了查,原来setState()
是异步操作,后面的 console.log(this.state.textContent)
执行的时候, state
还没更新完,所以输出的是之前的值。
原理如下——
setState ()
并不是刷新状态树的,它还要合并新旧状态并扫描虚拟DOM树找出受影响的节点,然后去更新节点上的UI部分,这是一件很耗时(相对而言)的事,所以会等一个时机去做批量更新,在这之前state
并不会被改变。
简而言之,就是你的数据其实已经改变并被存储在队列中了,只是这个状态还没来得及更新,因为当前事务(transaction
)还未走完。
只要脱离了当前事务,狭义点说只要不在当前函数里,你使用的textContent
和输入的textContent
还是保持一致的,不用担心。
当然了,如果真的不放心,setState
也是支持回调的,你可以通过以下代码获取数据:
this.setState({value: event.target.value}, () => console.log(this.state.value))
好啦,今天就到这儿,我们下次再见啦,ciao~ ciao~
网友评论