反应警告 useEffect 缺少依赖项

React warning useEffect missing dependency

在我的 React 应用程序中,我有一个 redux 存储,其中包含具有以下模型的用户:

{
  id: "",
  name: "",
  email: "",
  isAdmin: false,
  client: { id: undefined },
  token: "",
  tokenExpiry: null
};

在一个简单的页面上,我在数据库中查询与该用户关联的其他数据。为此,我利用了 useEffect 钩子:

  useEffect(() => {
    // Check JWT auth token and refresh if near expiry
    auth.refresh(
      { token: user.token, tokenExpiry: user.tokenExpiry },
      // Request user "field" data
      loadFields(user.client.id, user.token)
    );
  }, [user.client.id, user.token]);

构建时,React 会显示 React Hook useEffect has missing dependencies: 'loadFields' and 'user.tokenExpiry'. Either include them or remove the dependency array 警告。

如果我理解 useEffect 正确,第二个参数是 Reach 将 "watch" 的值,一旦发生任何更改,组件将重新渲染(类似于 componentDidUpdate 的工作方式)...

虽然在我的 useEffect 调用中使用了其他值,但我只想在 user.client.iduser.token 更改时重新处理此函数。这是为了避免在更改用户模型的其他部分时进行不必要的重新渲染,因此我不想添加 user.tokenExpiry 作为依赖项。

由于 loadFields 函数也是在 useEffect 逻辑之外使用的函数,我不能将它放在 useEffect 中,所以我尝试将它添加为依赖项,但这会导致重新渲染循环,因为其中有一个 dispatch 调用:

const loadFields = async (clientId, token) => {
  setIsLoading(true);
  try {
    await dispatch(fetchFields(clientId, token));
    setIsLoading(false);
  } catch (error) {
    setIsLoading(false);
    dispatch(resetFields());
  }
};

那么在这种情况下推动 useEffect 的正确方法是什么?

要么将所有依赖添加到数组

useEffect(() => {
  // Check JWT auth token and refresh if near expiry
  auth.refresh(
    { token: user.token, tokenExpiry: user.tokenExpiry },
    // Request user "field" data
    loadFields(user.client.id, user.token)
  );
}, [user.client.id, user.token, user.tokenExpiry]);

或者它可能只是被你的 react-hooks linter 标记,你可以为该行禁用它。

useEffect(() => {
  // Check JWT auth token and refresh if near expiry
  auth.refresh(
    { token: user.token, tokenExpiry: user.tokenExpiry },
    // Request user "field" data
    loadFields(user.client.id, user.token)
  );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user.client.id, user.token]);

我通常也会在覆盖上方留下评论,说明它的原因。请谨慎使用此选项,因为当您对效果挂钩进行任何更改时,它会更改您希望挂钩更改的内容 "watch"。

建议:将 tokenExpry 添加到数组并有条件地调用您的端点(如果您知道它即将需要刷新)。

useEffect(() => {
  // Check JWT auth token and refresh if near expire
  if ( /* tokenExpiry almost expired */ ) {
    auth.refresh(
      { token: user.token, tokenExpiry: user.tokenExpiry },
      // Request user "field" data
      loadFields(user.client.id, user.token)
    );
  }
}, [user.client.id, user.token, user.tokenExpiry]);

要在依赖列表中包含 loadFileds 函数,请尝试用 React.useCallback 挂钩将其包装起来

React.useCallback(async (clientId, token) => { ... }, []);

并将其添加到依赖列表。 useCallback "remembers" 函数并且不会在每次渲染时都创建它,因此 loadFields 在渲染中保持相同并且不会触发 effect,参见 Documentation.

那么 tokenExpiry - 好吧,有时会发生这种情况,我通常会发表评论,描述为什么某些变量不在依赖列表中。