如何修复使用 useEffect React Hook 时缺少依赖项警告
使用 React 16.8.6(在之前的版本 16.8.3 上表现良好),当我尝试阻止获取请求上的无限循环时出现此错误:
./src/components/BusinessesList.js
Line 51: React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array react-hooks/exhaustive-deps
我无法找到停止无限循环的解决方案。我想避免使用
useReducer()
。我确实找到了这个讨论
[ESLint] 'exhaustive-deps' lint 规则 #14920
,其中一个可能的解决方案是
如果您认为自己知道自己在做什么,您可以随时 // eslint-disable-next-line react-hooks/exhaustive-deps。
我对自己所做的事情没有信心,所以我还没有尝试实现它。
我有这个当前设置,
React hook useEffect 永远/无限循环持续运行
,唯一的评论是关于
useCallback()
我不太熟悉。
我目前如何使用
useEffect()
(我只想在开始时运行一次,类似于
componentDidMount()
):
useEffect(() => {
fetchBusinesses();
}, []);
const fetchBusinesses = () => {
return fetch("theURL", {method: "GET"}
)
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
};
如果您没有在效果之外的任何地方使用 fetchBusinesses 方法,您可以简单地将其移入效果并避免警告
useEffect(() => {
const fetchBusinesses = () => {
return fetch("theURL", {method: "GET"}
)
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
};
fetchBusinesses();
}, []);
但是,如果您在效果之外使用 fetchBusinesses,则必须注意两件事
-
当在 mount 期间使用
fetchBusinesses
及其封闭闭包时,您 不 将该方法作为方法传递,这是否存在问题? - 您的方法是否依赖于从其封闭闭包接收的一些变量?您不是这种情况。
- 在每次渲染时,fetchBusinesses 都会重新创建,因此将其传递给 useEffect 会导致问题。因此,如果要将 fetchBusinesses 传递给依赖项数组,则首先必须记住它。
总而言之,如果您在
useEffect
之外使用
fetchBusinesses
,则可以使用
// eslint-disable-next-line react-hooks/exhaustive-deps
禁用该规则,否则您可以将该方法移到 useEffect 内部
要禁用该规则,您可以这样编写
useEffect(() => {
// other code
...
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
如果您正在创建新应用或具有足够的灵活性,那么状态管理库有很多不错的选择。请查看 Recoil。
仅出于完整性考虑:
1.
(已停止工作)
使用函数作为
useEffect
回调
useEffect
回调
useEffect(fetchBusinesses, [])
2. 在
useEffect()
内声明函数
useEffect(() => {
function fetchBusinesses() {
...
}
fetchBusinesses()
}, [])
3.使用
useCallback()
进行记忆化
在这种情况下,如果您的函数中有依赖项,则必须将它们包含在
useCallback
依赖项数组中,如果函数的参数发生变化,这将再次触发
useEffect
。此外,它有很多样板...因此,只需将函数直接传递给
useEffect
,如
1. useEffect(fetchBusinesses, [])
所示。
const fetchBusinesses = useCallback(() => {
...
}, [])
useEffect(() => {
fetchBusinesses()
}, [fetchBusinesses])
4.函数的默认参数
It's not best practice, but it could be useful in some cases.
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
5. 创建自定义钩子
创建自定义钩子并在只需要运行一次函数时调用它。它可能更简洁。您还可以在需要时返回回调以重置重新运行“初始化”。
// customHooks.js
const useInit = (callback, ...args) => {
const [mounted, setMounted] = useState(false)
const resetInit = () => setMounted(false)
useEffect(() => {
if(!mounted) {
setMounted(true);
callback(...args);
}
},[mounted, callback]);
return [resetInit]
}
// Component.js
return ({ fetchBusiness, arg1, arg2, requiresRefetch }) => {
const [resetInit] = useInit(fetchBusiness, arg1, arg2)
useEffect(() => {
resetInit()
}, [requiresRefetch, resetInit]);
6. 禁用 eslint 的警告
禁用警告应该是您的最后手段,但当您这样做时,最好 内联且明确地 执行,因为未来的开发人员可能会感到困惑或在不知道 linting 已关闭的情况下创建意外的错误
useEffect(() => {
fetchBusinesses()
}, []) // eslint-disable-line react-hooks/exhaustive-deps
./src/components/BusinessesList.js
Line 51: React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array react-hooks/exhaustive-deps
这不是 JavaScript/React 错误,而是 ESLint (eslint-plugin-react-hooks) 警告。
它告诉您该钩子依赖于函数
fetchBusinesses
,因此您应该将其作为依赖项传递。
useEffect(() => {
fetchBusinesses();
}, [fetchBusinesses]);
如果该函数在类似组件中声明,则可能导致在每次渲染时调用该函数:
const Component = () => {
/*...*/
// New function declaration every render
const fetchBusinesses = () => {
fetch('/api/businesses/')
.then(...)
}
useEffect(() => {
fetchBusinesses();
}, [fetchBusinesses]);
/*...*/
}
因为每次都会用新的引用重新声明该函数。
执行此操作的正确方法是:
const Component = () => {
/*...*/
// Keep the function reference
const fetchBusinesses = useCallback(() => {
fetch('/api/businesses/')
.then(...)
}, [/* Additional dependencies */])
useEffect(() => {
fetchBusinesses();
}, [fetchBusinesses]);
/*...*/
}
或者只是在
useEffect
。