英文:
Does useEffect with props in its dependency array rerun whenever the component renders?
问题
如在React文档的useEffect部分所示,通常应该在useEffect
的依赖数组中包含props
:
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
我在某处读到,传递给React组件的props
对象在每次渲染时都会发生变化。即使对象的属性(键和值)可能相同,但在每次渲染之间它不是相同的对象。
在上面的示例中,假设roomId
实际上是一个对象(而不仅仅是一个数字),那么即使roomId
对象的键和值没有更改,useEffect
是否不会在每次渲染时重新运行?
附注:最终目标是理解上述问题,以便只在解构后的props
对象的键和值发生变化时运行效果。
英文:
As seen under the useEffect section of the React docs, props should generally be included in useEffect's dependency array:
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
I have read somewhere that the props object passed to a react component always changes on each render. I.e. it is not the same object from one render to the next, even though the object's properties (keys and values) may be the same.
In the example above, assuming roomId
was actually an object (and not just a number), does the useEffect not re-run on every render, even if roomId object's keys and values did not change?
Side note: As an end goal, I would like to understand the above so I can run an effect only if my destructured props object's keys and values changed.
答案1
得分: 1
您的道具对象可能会在每次渲染时更改,但在确定何时触发效果钩子时,将比较效果钩子依赖中使用的值,而不是它们可能是一部分的任何对象。
演示....
const roomId = { id: 123 };
const props1 = { roomId };
const props2 = { roomId };
console.log("props 相等吗?", props1 === props2); // false
console.log("roomId 相等吗?", props1.roomId === props2.roomId); // true
只要在每个渲染周期中使用的相同值(或对象引用)存在,您的效果钩子就不会重新运行。
这就是为什么 react-hooks/exhaustive-deps ESLint 规则特别提到...
但是,'props' 会在任何 prop 更改时发生更改,因此首选的修复方法是在 useEffect 调用之外解构 'props' 对象,并在 useEffect 中引用那些特定的 props。
如果您不能保证对象的相等性,那么我建议拿出您可以识别的任何属性
function ChatRoom({ roomId: { id } }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
// ...
}, [serverUrl, id]);
}
英文:
While your props object might change with each render, the values used in the effect hook dependencies are compared when determining when to trigger, not any objects they might be part of.
To demonstrate....
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const roomId = { id: 123 };
const props1 = { roomId };
const props2 = { roomId };
console.log("props equal?", props1 === props2); // false
console.log("roomId equal?", props1.roomId === props2.roomId); // true
<!-- end snippet -->
So as long as the same value (or object reference) used in your hook dependencies is present in each render cycle, your effect hook will not re-run.
This is why the react-hooks/exhaustive-deps ESLint rule has a special mention...
> However, 'props' will change when any prop changes, so the preferred fix is to destructure the 'props' object outside of the useEffect call and refer to those specific props inside useEffect.eslint(react-hooks/exhaustive-deps)
If you cannot guarantee object equality, then I would recommend pulling out whatever identifying properties you can
function ChatRoom({ roomId: { id } }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
// ...
}, [serverUrl, id]);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论