如何解决React Hook useEffect缺少依赖项的exhaustive-deps规则报错?
报错原因
这个是React官方的react-hooks/exhaustive-deps ESLint规则的校验提示:要求useEffect回调中用到的所有外部变量,都必须声明在useEffect的第二个参数依赖数组中。你当前的useEffect里用到了fetchUserName和history两个外部变量,但没有加到依赖数组里,因此触发报错。
最优解决方案(推荐)
将仅在useEffect中使用的fetchUserName函数移到useEffect内部,再把history加到依赖数组即可。react-router返回的history实例引用是稳定的,不会导致useEffect意外重复执行。
改后完整代码如下:
import React, { useEffect, useState } from "react"; import { useAuthState } from "react-firebase-hooks/auth"; import { useHistory } from "react-router"; import "./Dashboard.css"; import { auth, db, logout } from "./firebase"; function Dashboard() { const [user, loading] = useAuthState(auth); const [name, setName] = useState(""); const history = useHistory(); useEffect(() => { // 将fetchUserName移到effect内部,无需再作为依赖声明 const fetchUserName = async () => { try { const query = await db .collection("users") .where("uid", "==", user?.uid) .get(); const data = await query.docs[0].data(); setName(data.name); } catch (err) { console.error(err); alert("An error occured while fetching user data"); } }; if (loading) return; if (!user) return history.replace("/"); fetchUserName(); // 补全所有用到的外部依赖:user、loading、history }, [user, loading, history]); return ( <div className="dashboard"> <div className="dashboard__container"> Logged in as <div>{name}</div> <div>{user?.email}</div> <button className="dashboard__btn" onClick={logout}> Logout </button> </div> </div> ); } export default Dashboard;
备选方案:需要在外部复用fetchUserName的情况
如果fetchUserName还需要在effect之外的其他地方调用,可以用useCallback包裹函数稳定引用,再补全依赖即可:
// 仅展示修改部分代码 const fetchUserName = useCallback(async () => { try { const query = await db .collection("users") .where("uid", "==", user?.uid) .get(); const data = await query.docs[0].data(); setName(data.name); } catch (err) { console.error(err); alert("An error occured while fetching user data"); } // 声明fetchUserName的依赖 }, [user, setName]); useEffect(() => { if (loading) return; if (!user) return history.replace("/"); fetchUserName(); // 补全所有依赖 }, [user, loading, history, fetchUserName]);
不推荐的临时绕开方案
如果你确定当前依赖数组的逻辑没问题,也可以加注释跳过ESLint校验,但该方式会隐藏潜在的依赖更新问题,不建议常规使用:
useEffect(() => { if (loading) return; if (!user) return history.replace("/"); fetchUserName(); // 跳过依赖校验 // eslint-disable-next-line react-hooks/exhaustive-deps }, [user, loading]);
内容的提问来源于stack exchange,提问作者Ahmed Labeeb
相关产品推荐
相关产品推荐

