我在显示单个数据项的组件(InternalComponent)中有两个useEffect挂钩.一个useEffect将计数作为状态进行跟踪,当用户增加计数时将其发送到数据库.第二个useEffect在InternalComponent跟踪的项目发生更改(由于外部操作)时重置计数.
问题是:更新数据库的useEffect会在项目更改时触发;它将看到新的项目值,但会错误地向数据库发送previous个项目的计数.发生这种情况是因为两个useEffects"同时"触发,并且在运行POST useEffect之前,不应设置指示计数的状态.
const InternalComponent = ({ item }) => {
const [count, setCount] = useState(item.count);
const [countChanged, setCountChanged] = useState(false);
useEffect(() => {
console.log(
`Item is now ${item.id}; setting count from item and marking unchanged.`
);
setCount(item.count);
setCountChanged(false);
}, [item]);
useEffect(() => {
if (countChanged) {
console.log(
`Count changed for item ${item.id}, POSTing (id=${item.id}, count=${count}) to database.`
);
} else {
console.log(
`Count hasn't changed yet, so don't update the DB (id=${item.id}, count=${count})`
);
}
}, [item, count, countChanged]);
const handleButtonClick = () => {
setCount(count + 1);
setCountChanged(true);
};
return (
<div>
I'm showing item {item.id}, which has count {count}.<br />
<button onClick={handleButtonClick}>Increment item count</button>
</div>
);
};
代码Sandbox 上的最小工作示例:https://codesandbox.io/s/post-with-stale-data-vfzh4j?file=/src/App.js
注释输出:
1 (After button click) Count changed for item 1, POSTing (id=1, count=6) to database.
2 (After item changed) Item is now 2; setting count from item and marking unchanged.
3 Count changed for item 2, POSTing (id=2, count=6) to database.
4 (useEffect runs twice) Count hasn't changed yet, so don't update the DB (id=2, count=50)
第3行是不需要的行为:数据库将收到一个带有错误项目ID的帖子,理想情况下根本不应该发送.
这感觉像是一个简单/常见的问题:我应该使用什么设计来防止POST useEffect在过时状态下触发?我很容易想到的所有解决办法在我看来都是荒谬的.(例如, for each 项目创建一个内部组件,只显示其中一个,将所有useEffects组合成一个巨大的useEffect,跟踪组件中的每个状态,等等)我肯定忽略了一些显而易见的事情:有什么 idea 吗?非常感谢.