我是React
的新手,我创建了一个最小的测试应用程序来说明scope
的问题。
import React, { useState, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
function useCounter(topic, defaultMsg) {
const [message, setMessage] = useState(defaultMsg);
const increment=() =>{
console.log("increment from " + message);
setMessage(message+1);
}
return [message, increment];
}
export default function App() {
const [counter, incrementCounter] = useCounter("anyData", 0);
return (
<div>
<p>you clicked: {counter} times</p>
<button
onClick={() => {
console.log("sending ");
incrementCounter(counter); //works
incrementCounter(counter); //doesn't work because using the old scope
}}
>
Click me
</button>
</div>
);
}
输出
App.js:10 increment from 0
App.js:10 increment from 0 //should be 1
App.js:27 sending
App.js:10 increment from 1
App.js:10 increment from 1 //should be 2
如果按下按钮,则incrementCounter
被调用两次。预期的行为:每次单击都会使计数器增加2。但是,这并不是因为useCounter
钩似乎使用了message的旧值。因此,每次点击都会使计数器增加1。我知道为什么这样不起作用,也不知道如何解决。
您将如何解决该问题?
答案 0 :(得分:1)
问题是事件处理程序中的状态更新调用是成批处理的,因此在不使用回调方法的情况下多次调用setState不会正确更新值
思考代码
incrementCounter(counter);
incrementCounter(counter);
为
setMessage(message + 1);
setMessage(message + 1);
现在,这两个调用已合并,将应用于setState的最终更改为message + 1
,其中1
。
状态更新也是异步的,不会立即反映出来
如果将setMessage实现更改为function state update
setMessage(prevMessage => prevMessage+1);
您将看到期望的输出,因为在这种情况下,批处理不是由react执行的,并且状态将增加两次。但是,由于setState的异步特性,您仍将在控制台中看到相同的输出