我在useState
React钩子上遇到了一些非常奇怪的行为。在下面的代码(https://codesandbox.io/s/purple-bush-nb5uy?file=/src/index.js)中:
function App() {
return (
<div className="App">
<Comp flag={true} />
</div>
);
}
const Comp = ({ flag }) => {
const [running, setRunning] = useState(false);
const [jumping, setJumping] = useState(false);
console.log('zero');
const setBoth = () => {
setRunning(true);
console.log('one');
setJumping(true);
console.log('two');
};
return (
<>
{"running: " + running}
{"jumping: " + jumping}
<button onClick={() => setBoth()}>setboth</button>
</>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
当我们单击button
时,我们将在控制台中获得以下序列:
one
two
zero
我希望:
zero
one
zero
two
因为我认为React会立即重新渲染,如果它找到一个useState
setter,下面的代码会在重新渲染后执行。此外,我的React应用程序就是这样:
const [time, setTime] = useState('');
console.log('Hey');
const updateTime = (e) => {
setTime(e.details);
console.log('Hello');
};
useEffect(() => {
window.addEventListener("updateTime", updateTime);
return () => {
window.removeEventListener("updateTime", updateTime);
}
}, []);
当updateTime
运行并且e.details
的值与状态变量time
的内容不同时,上面的代码会发生什么:
Hey
Hello
换句话说,重新呈现首先运行,设置器之后的代码随后运行。那么,为什么我们在上述情况下会有不同的行为呢?解释是什么,引擎盖下发生了什么?
3条答案
按热度按时间6tdlim6h1#
根据 * 丹·阿布拉莫夫 *(联合创作者:Redux,Create React App.)
目前(React 16及更早版本),默认情况下只有React事件处理程序内部的更新是批量处理的。有一个不稳定的API可以在您需要时在事件处理程序之外强制执行事件处理程序,以应对罕见的情况。
无论你在React事件处理程序中执行了多少次setState()调用,它们都只会在事件结束时产生一个re-render
在第一种情况下,click事件是一个react事件,
作者:Dan Abramov
然而,在React 16和更早的版本中,在React事件处理程序之外,默认情况下还没有react。因此,如果在您的示例中,我们有一个AJAX响应处理程序而不是WebClick,那么每个setState()都会立即被处理。在这种情况下,是的,你会看到一个中间状态:
window. addEventEvent不是一个react事件,所以它应该立即呈现。
你可以在这里找到 Dan Abramov 的完整答案
我制作了一个包含两个场景的here示例
mrphzbgm2#
这是预期的行为,react通常只在状态或 prop 改变时才重新渲染组件。React的
useState
是一个异步函数,这就是console.log命令不匹配的原因。您可以使用
useEffect
来监听更改并根据需要触发函数。Codesandbox link
9w11ddsr3#
上面的代码被称为“”。这意味着react在后台通过同时调用setRunning和setJumping来更新。这将导致单个重新渲染。
因此,当您单击更改两种状态的按钮时,两种状态都会立即设置。因此,我们打印
//“1”
//“2”
//“3”=>再次渲染后。
React Effect是一个react钩子,在重新渲染后调用。
因此,首先打印“嘿”=>组件已渲染
接下来,useEffect被调用,因为useEffect在重新渲染后被react调用。
因此,它打印“Hello”。