react类组件异步更新,何时会同步,常报的错误
1、关于this.setState()
解决因为异步不能取到想要的值的:
1)this.setState()可接收一个函数作为参数
这个函数将接收两个参数,将前一个状态作为第一个参数,应用更新时的 props 作为第二个参数,如下:
this.setState((prevState, props) => ({
number: prevState.number + props.increment
}));
2)执行setState()后能拿到最新的state值
setState()函数接收两个参数,一个是一个对象,表示更新当前的状态,一个是回调函数,是在设置状态成功之后调用,所以我们可以通过回调拿到最新的state值。代码如下:
updateNum = (arg) => {
this.setState(
{ number: arg },
() => {
console.log(this.state.number);//输出最新number值
}
);
}
React会把this.state放到队列中,将它的更新设置成批处理,所以由 React 控制的事件处理过程 setState 不会同步更新 this.state!
也就是说,在 React 控制之外的情况, setState 会同步更新 this.state,绕过 React 通过 JavaScript 原生 addEventListener 直接添加的事件处理函数,还有使用 setTimeout/setInterval 等 React 无法掌控的 APIs情况下,就会出现同步更新 state 的情况。
咱就是举个🌰 来说:
class Finish extends PureComponent<Props> {
state = {
count: 1
}
componentDidMount() {
document.querySelector('#btn-raw').addEventListener('click', this.onClick);
}
//这里不是在Button组件里使用onClick,而是用JavaScript 原生 addEventListener 直接添加的事件处理函数
onClick=()=> {
this.setState({ count: this.state.count + 1 });
console.log('# this.state', this.state);
}
render() {
console.log('#enter render', this.state);
return (
<div>
<div>{this.state.count}
<button id="btn-raw">Increment Raw</button>
</div>
</div>
)
}
}
export default Finish
这样在浏览器能实时的输出count,同步实现加一操作
在这里讲一下我犯的错误,初次写这段代码我是这样写的
onClick(){
this.setState({ count: this.state.count + 1 });
console.log('# this.state', this.state);
}
导致报错:TypeError: Cannot read property ‘count’ of undefined
我想看看这个setState怎么回事,于是报了新的错误:
TypeError: this.setState is not a function
可是组件在第一次render的时候明明输出了count
经过排查才发现,是this指向出了问题,让我们来看看剪头函数和普通函数在react类组件中的指向:
在箭头函数中this指向当组件Finish;而在普通函数中this指向的是button按钮:
所以在触发点击事件之后它找不到this里面的state,因为根本没有
解决方法一:
最简单的就是用箭头函数
解决方法二:
bind绑定this
constructor(props){
super(props)
this.state = {
count: 1
}
this.onClick=this.onClick.bind(this)//此处不能偷懒直接写等号右边的,一定要写完整,否则绑定失败还是报错
}
componentDidMount() {
document.querySelector('#btn-raw').addEventListener('click', this.onClick);
}
onClick(){
console.log(this,'=====')
}
2、在React中与state有关的报错
1)Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
报错原因:
a、在网速慢的情况的,你去请求数据。然后看没有数据时,又返回出去了,等于你将组件卸载了,可过了一会数据回来之后,会报该错。
b、组件已经被销毁,而此时我们的异步操作(通常为调用接口更改state操作)还未结束。当我们的异步执行完成后要执行setState操作时,已经无法获得组件信息,由此造成该异常!
c、在组件挂载(mounted)之后进行了异步操作,比如ajax请求或者设置了定时器等,而你在callback中进行了setState操作。当你切换路由时,组件已经被卸载(unmounted)了,此时异步操作中callback还在执行,因此setState没有得到值。
解决方法:
法一:在卸载的时候对所有的操作进行清除(例如:abort你的ajax请求或者清除定时器)
componentWillUnMount = () => {
//1.ajax请求
$.ajax.abort()
//2.定时器
clearTimeout(timer)
}
法二:定个开关,组件卸载时候重置开关
componentDidMount = () => {
this.flag = true;
axios.get({'你的请求'})
.then(res => {
if(this.flag){
this.setState({
aa:true
})
}
})
.catch(err => {})
}
componentWillUnMount = () => {
this.flag = false;
法三:万金油
//以下三种写法都 🉑️
componentWillUnmount = () => {
this.setState = (state,callback)=>{
return;
};
}
componentWillUnmount() {
this.setState = ()=>false;//撤销setState
}
componentWillUnmount() {
this.setState = ()=>{};//直接将setState重写
}