根据官方的React文档,componentDidMount
在钩子中翻译为:
useEffect(() => {
//code here
},[])
因此,假设我想在此挂钩中进行api调用:
useEffect(() => {
getActiveUser();
},[])
添加eslint规则"react-hooks/exhaustive-deps"
之后,这是一个皮棉错误。为了使它静音,我可以将getActiveUser
函数放在数组中,然后一切正常。
但这是否违反文档?我的印象是该数组检查道具更改。我还要指出,API调用是在没有prop / id的情况下进行的,因此我可以理解必须执行以下操作的事实:
useEffect(() => {
getActiveUser(someId);
},[getActiveUser, someId])
那么这是怎么回事?添加Eslint规则意味着效果内的数组不能再次为空?
答案 0 :(得分:3)
声明getActiveUser
的位置很重要。该问题未指定,但我认为您的组件看起来像这样:
const MyComponent = (props) => {
const getActiveUser() => {
//...
}
useEffect(() => {
getActiveUser();
}, []) // Lint error.
return <></>;
}
如果相反,您的组件看起来像这样,则不会出现短绒毛错误:
const getActiveUser() => {
//...
}
const MyComponent = (props) => {
useEffect(() => {
getActiveUser();
}, []) // No error
return <></>;
}
那么为什么第一个是linter错误,而第二个不是?短绒规则的重点是要避免由于过时的道具或状态而引起的问题。尽管getActiveUser
本身不是道具或状态,但在组件内部定义时,它可能取决于道具或状态,这可能是陈旧的。
考虑以下代码:
const MyComponent = ({userId}) => {
const [userData, setUserData] = useState(null);
const getActiveUser() => {
setUserData(getData(userId)); // More realistically this would be async
}
useEffect(() => {
getActiveUser();
}, []);
//...
}
即使useEffect
依赖于userId
道具,它也只能运行一次,因此,{{1}和userId
将在{{ 1}}的更改。也许这是您的意图,但就短绒规则而言,它看起来像是个错误。
在userData
是在组件外部定义的情况下,它不可能(或至少不是合理地)依赖于组件的状态或属性,因此linter规则没有问题。 / p>
那么如何解决这个问题?好吧,如果不需要在组件内部定义userId
,只需将其移出组件即可。
或者,如果您确定只希望在组件安装时运行此行为,并且不会因道具更改而引起问题(最好假设所有道具都可以更改),则只需禁用短绒规则。
但是假设都不是这样...
如前所述,在棉绒阵列中添加getActiveUser
可以解决问题:
getActiveUser
但是getActiveUser
是每个渲染的不同函数实例,因此就const MyComponent = ({userId}) => {
const getActiveUser() => {
//...
}
useEffect(() => {
getActiveUser();
}, [getActiveUser]) // No error... but probably not right.
return <></>;
}
而言,deps数组会更改每个渲染,这将在每次渲染后引起API调用,这几乎可以肯定不是你想要的。
由于在我的示例中,根本问题是getActiveUser
属性可能会发生变化,因此您还可以通过在useEffect
依赖项中添加userId
来解决此问题:
userId
这是正确的行为-没有额外的API调用或过时的数据-但是linter仍然不满意:知道我们已经通过依赖于所有事物来解决对useEffect
的依赖关系是不够聪明的const MyComponent = ({userId}) => {
const getActiveUser() => {
// Uses userId
}
useEffect(() => {
getActiveUser();
// Linter is still unhappy, so:
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userId])
return <></>;
}
取决于。
这很脆弱:如果您将来添加getActiveUser
所依赖的道具或状态,而忘记在此处添加它,那么您将遇到过时的数据问题。
所以推荐的解决方案是:
getActiveUser
通过将getActiveUser
包装在const MyComponent = ({userId}) => {
const getActiveUsers = useCallback(() => {
// uses userId
}, [userId]);
useEffect(() => {
getActiveUser();
}, [getActiveUsers]) // No error
return <></>;
}
中,仅在需要时替换函数实例:getActiveUsers
发生变化时。这意味着useCallback
也仅在需要时运行:userId
发生更改时(即useEffect
发生更改时)。
短毛绒对此解决方案感到满意,如果您将新的依赖项引入getActiveUsers
,则只需更改其userId
部门,而无需更改getActiveUser
。
Dan Abramov的博客文章A Complete Guide to useEffect
对此进行了更详细的介绍。