我正在创建一个使用react-hooks和一系列计时器构建的计时器应用程序 我不明白为什么timerList会改变
这是父组件
const [timerList, setTimerList] = useState([]);
const removeTimer = () => {
console.log("timerList", timerList);
};
return (
<div id="main">
{timerList ? timerList.map((child) => child) : null}
<div className="add-button before">
<button
onClick={() => {
const time = new Date();
time.setSeconds(time.getSeconds() + 0);
setTimerList((timerList) => [
...timerList,
<FullTimer
expiryTimestamp={time}
removeTimer={() => {
removeTimer();
}}
id={window.prompt("Insert timer name") + ` ${timerList.length}`}
key={timerList.length}
/>,
]);
}}
>
感兴趣的 child 的组成部分:
<button
onClick={() => {
removeTimer();
}}
>
子组件是一个带有一些CSS的自定义计时器,当我调用removeTimer时,timerList(在父组件中)的值会发生变化,而它应该保持不变。
我错过了什么?
附注按钮标签没有关闭,因为我里面有一些使用 Awesome-font 的元素
最佳答案
旁注:一般来说,将组件存储在另一个组件状态中被认为是不好的做法。
但这并不是真正的问题。给定您的代码,它是 simple closure problem .
这个:
const removeTimer = () => {
console.log("timerList", timerList);
};
定义关闭当前timerList
。因此它会记录它,就像分配removeTimer
时一样。目前,每个渲染都会出现这种情况。因此它会记录看似落后一步的状态。这个问题没有解决办法,因为闭包就是这样工作的。
如果您确实想要删除计时器,则在调用 removeTimer
时,您需要使用更新程序的回调版本 (setTimerList
) 并传递一些标识值这样您就可以真正删除正确的一个。
如果您遵循最初的建议并且不将组件存储在状态中,而是定义属性,那么这一切都会简单得多。
以下是一个工作示例(请原谅我的 typescript ):
import React, { useState } from 'react';
type FullTimerProps = {
id: string;
expiryTimestamp: Date;
removeTimer: () => void;
}
const FullTimer = ({expiryTimestamp, removeTimer, id}: FullTimerProps): JSX.Element => {
return (
<div>
<button onClick={removeTimer}>remove</button>
{id}: {expiryTimestamp.toLocaleDateString()}
</div>
);
};
type Timer = {
id: string;
expiryTimestamp: Date;
};
const TimerList = (): JSX.Element => {
const [timerList, setTimerList] = useState<Timer[]>([]);
const removeTimer = (timer: Timer) => {
setTimerList(timerList => timerList.filter(t => t.id !== timer.id));
};
return (
<div id="main">
{timerList.map(timer => (
<FullTimer
key={timer.id}
id={timer.id}
expiryTimestamp={timer.expiryTimestamp}
removeTimer={() => removeTimer(timer)}
/>
))}
<div className="add-button before">
<button
onClick={() =>
setTimerList(timerList => [...timerList, {
id: window.prompt('Insert timer name') + ` ${timerList.length}`,
expiryTimestamp: new Date()
}])}
>Add
</button>
</div>
</div>
);
};
关于javascript - 当我从子进程调用它时,useState 值会发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68748985/