问题的最小示例,2021
问题:你有这个代码,它创建了一个无限循环。这是因为array
是在依赖数组中,并且您setArray
在每次运行 时useEffect
,这意味着它将继续被设置。
const MyComponent = ({ removeValue }) => {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
// useEffect to remove `removeValue` from array
useEffect(() => {
const newArray = array.filter((value) => value !== removeValue);
setArray(newArray);
}, [array, removeValue]);
return <div>{array.join(" ")}</div>;
};
有多种解决方案:
解决方案#1:使用之前的状态
该setState
也可以采取一个回调,它给你的当前状态作为参数。这有时可以用来解决问题。现在你不需要包含array
在依赖数组中:
const MyComponent = ({ removeValue }) => {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
// useEffect to remove `removeValue` from array
useEffect(() => {
setArray((previousArray) => {
const newArray = previousArray.filter((value) => value !== removeValue);
return newArray;
});
}, [removeValue]);
return <div>{array.join(" ")}</div>;
};
解决方案#2:有条件地运行 useEffect
有时您可以找到运行useEffect
. 例如,我们只需要array
在数组包含removeValue
. 因此我们可以早点返回:
const MyComponent = ({ removeValue }) => {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
// useEffect to remove `removeValue` from array
useEffect(() => {
const containsValue = array.includes(removeValue);
if (!containsValue) return;
const newArray = array.filter((value) => value !== removeValue);
setArray(newArray);
}, [array, removeValue]);
return <div>{array.join(" ")}</div>;
};
解决方案#3:使用 useCompare
有时由于限制,上述解决方案是不可能的,所以这里有一个更复杂的方法。这是针对更复杂的问题,但我还没有看到useEffect
它无法解决的问题。它需要我将在下面提供的两个附加功能。
我对下面的代码进行了评论以解释该功能:
const MyComponent = ({ removeValue }) => {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
// useCompare will return either `true` or `false` depending
// on if the value has changed. In this example, `useEffect` will
// rerun every time the array length changes.
// This can be applied to any other logic such as if removeValue
// changes, depending on when you want to run the `useEffect`
const arrayLengthChanged = useCompare(array.length);
useEffect(() => {
if (!arrayLengthChanged) return;
const newArray = array.filter((value) => value !== removeValue);
setArray(newArray);
}, [array, arrayLengthChanged, removeValue]);
return <div>{array.join(" ")}</div>;
};
解决方案#4:禁用错误(不推荐)`
最后一个“解决方案”是避免这个问题。在某些情况下,这已经足够了,并且可以完美运行,但如果useEffect
稍后进行更改或未正确使用,则可能会导致调试问题。
在此示例中,假设您知道永远不需要运行useEffect
when 数组更改,您只需将其从依赖项数组中删除并忽略错误:
const MyComponent = ({ removeValue }) => {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
// useEffect to remove `removeValue` from array
useEffect(() => {
const newArray = array.filter((value) => value !== removeValue);
setArray(newArray);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [removeValue]);
return <div>{array.join(" ")}</div>;
};