我有一个使用钩子(Hook)的函数组件。在 useEffect Hook 中,我只想从后端获取数据并将结果存储在状态中。然而,尽管添加了 data 变量作为依赖项,useEffect 仍然会触发无限循环 - 即使数据没有更改。如何阻止 useEffect 连续触发?
我尝试过空数组 hack,它确实阻止了 useEffect 的连续触发,但这不是所需的行为。例如,如果用户保存新数据,则 useEffect 应该再次触发以获取更新的数据 - 我不想模拟 componentDidMount。
const Invoices = () => {
const [invoiceData, setInvoiceData] = useState([]);
useEffect(() => {
const updateInvoiceData = async () => {
const results = await api.invoice.findData();
setInvoiceData(results);
};
updateInvoiceData();
}, [invoiceData]);
return (
<Table entries={invoiceData} />
);
};
我预计 useEffect 在初始渲染后触发,并且仅在发票数据更改时再次触发。
最佳答案
useEffect 依赖项数组的工作方式是检查先前渲染和新渲染的数组中所有项目之间的严格 (===
) 等效性。因此,将数组放入 useEffect 依赖项数组中是非常麻烦的,因为与 ===
进行数组比较会通过引用检查等效性,而不是通过内容。
const foo = [1, 2, 3];
const bar = foo;
foo === bar; // true
const foo = [1, 2, 3];
const bar = [1, 2, 3];
foo === bar; // false
在效果函数内部,当您执行 setInvoiceData(results)
操作时,您会将 invoiceData
更新为新数组。即使该新数组中的所有项目完全相同,对新 invoiceData
数组的引用也会发生变化,导致效果的依赖关系不同,从而触发再次发挥作用——无限循环。
一个简单的解决方案是从依赖项数组中删除 invoiceData
。这样,useEffect 函数的作用基本上与 componentDidMount 类似,它会在组件首次渲染时触发一次且仅触发一次。
useEffect(() => {
const updateInvoiceData = async () => {
const results = await api.invoice.findData();
setInvoiceData(results);
};
updateInvoiceData();
}, []);
这种模式非常常见(并且有用),甚至在 the official React Hooks API documentation 中提到过。 :
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.
关于reactjs - 尽管依赖项没有变化,useEffect 仍运行无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57859484/