Reactjs 无法使用useState以编程方式更改组件的值
我试图在使用Reactjs 无法使用useState以编程方式更改组件的值,reactjs,material-ui,Reactjs,Material Ui,我试图在使用useStatehook时以编程方式更改状态 我是这样定义的: const [data, setData] = React.useState({ text: "Hello StackOverflow!", someNumber: 2 }); 出于测试目的,我创建了一个间隔,它每秒钟增加someNumber setInterval(() => { setData({ ...data, someNumber: data.someNumber + 1 }); },
useState
hook时以编程方式更改状态
我是这样定义的:
const [data, setData] = React.useState({
text: "Hello StackOverflow!",
someNumber: 2
});
出于测试目的,我创建了一个间隔,它每秒钟增加someNumber
setInterval(() => {
setData({ ...data, someNumber: data.someNumber + 1 });
}, 1000);
当我现在安装组件时,文本开始以不同的数字快速闪烁。我想间隔已经开始多次了,但我不知道为什么。这是我第一个使用新钩子的项目
可以找到我的代码的完整示例
如果链接断开,下面是组件:
import React from "react";
import TextField from "@material-ui/core/TextField";
export default function StateTextFields() {
const [data, setData] = React.useState({
text: "Hello StackOverflow!",
someNumber: 2
});
setTimeout(() => {
setData({ ...data, text: "How are you?" });
}, 1000);
setInterval(() => {
setData({ ...data, someNumber: data.someNumber + 1 });
}, 1000);
return (
<TextField
id="standard-name"
label="Name"
value={data.text + " " + data.someNumber}
margin="normal"
/>
);
}
从“React”导入React;
从“@material ui/core/TextField”导入TextField;
导出默认函数StateTextFields(){
const[data,setData]=React.useState({
文本:“你好,StackOverflow!”,
数字:2
});
设置超时(()=>{
setData({…数据,文本:“你好吗?”});
}, 1000);
设置间隔(()=>{
setData({…data,someNumber:data.someNumber+1});
}, 1000);
返回(
);
}
您正在为每个组件渲染调用设置setTimeout
和setInterval
。将setInterval
移动到useffect
内部。这将阻止它在每次渲染时创建新的间隔
React.useffect(()=>{
设置间隔(()=>{
setData(prevState=>({…prevState,someNumber:prevState.someNumber+1}));
}, 1000);
设置超时(…)
},[])
这将使这些函数在安装组件时只运行一次
无条件地调用修改函数组件内部状态的函数就像在类组件的呈现中执行相同操作一样。它将修改状态,这将导致重新渲染,这将无限地修改状态,等等
您需要使用prevState
回调进行更新。这是因为useffect
没有像useffect(()=>{},[data])
makingdata
那样监听对数据所做的更改。但我们也不想改变它来听变化,因为这会导致你的间隔被无限地再次创造出来。因此,我们使用prevState
,它始终使用状态的最新副本。每次重新渲染时都会触发超时/间隔。您必须将它放入一个useffect
中,它取代了生命周期挂钩,如componentDidMount()
例如:
useEffect(()=>{
const myInterval = setInterval(() => {
setData({ ...data, someNumber: data.someNumber + 1 })
}, 1000);
return ()=>{myInterval.clearInterval()} //cleanup
}, []) //The empty array means "only do this once, after the first render"
这里有很多问题
您正在设置处理相同数据的多个超时/间隔。由于异步性,它们在不同的时间段更新相同的值。例如:
超时
几乎与间隔
同时更改数据
。这导致超时计算2+1
,同时间隔考虑数据。一些数字仍然是2
,而不是3
当不使用像React这样的钩子时,useEffect
React将在每次重新启动组件时重新创建方法,即每次状态更改时重新创建方法,即每次数据更改时重新创建方法
正如所指出的,以下解决方案解决了这些问题。我添加了一些注释来解释原因
React.useffect(()=>{
设置间隔(()=>{
//在这里使用prevState很重要,因为它不需要“数据”作为
//这将迫使您在每次“数据”更改时重新创建钩子
setData(prevState=>({…prevState,someNumber:prevState.someNumber+1}));
}, 1000);
设置超时(…)
},[])
刚刚在您的沙箱上测试过。当将更新功能更改为如我的回答所示时,它将按预期工作。谢谢!成功了。伟大的我更新了我的答案,解释了为什么我们必须这样做。