【问题标题】:useEffect dependencies when using NextJS router使用 NextJS 路由器时的 useEffect 依赖项
【发布时间】:2021-11-11 03:47:32
【问题描述】:

我有一个 NextJS 项目,使用 NextJS 路由器根据某个状态变量将用户路由到页面。

我查找了如何使用 NextJS router documents 执行我想要的操作,其中包含以下示例:

const useUser = () => ({ user: null, loading: false })

export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()

  useEffect(() => {
    if (!(user || loading)) {
      router.push('/login')
    }
  }, [user, loading])

  return <p>Redirecting...</p>
}

当我将该示例粘贴到我的代码中时,ESLint 对我没有将路由器作为依赖项包含在内感到不高兴 - 显示以下消息:

React Hook useEffect has a missing dependency: 'router'. Either include it or remove the dependency array.eslintreact-hooks/exhaustive-deps

消息是有道理的——我们在效果中使用了 useRouter 挂钩,但没有将它添加到效果的依赖数组中。

但是,将它添加到依赖数组自然会导致无限的重新渲染循环(因为我使用的是动态路由,因此由于路由器正在更改,因此会一遍又一遍地调用相同的效果)。

我应该忽略 ESLint 的警告,还是应该一起做一些不同的事情?

编辑:值得注意的是我使用的是NextJS ESlint config

【问题讨论】:

  • 该问题的讨论是here。虽然我没有找到具体的解决方案。

标签: reactjs next.js use-effect


【解决方案1】:

目前,这是一个错误。

useRouter 方法似乎改变了useRouter 本身。因此,每次您调用其中一种方法时,useRouter 都会发生变化并导致此循环。

另一个问题是 Next.js 没有记住useRouter,所以即使值相同,它也会改变。

目前,我发现的最接近的解决方法来自对此未决问题 https://github.com/vercel/next.js/issues/18127#issuecomment-950907739 的评论。

它的作用是将useRouter“转换”为useRef并导出push方法。所以每次你使用这个方法时,如果值没有改变,这个引用就不会改变。

解决方法:

我很快想到了这个,这似乎奏效了:

import { useRouter } from 'next/router'
import type { NextRouter } from 'next/router'
import { useRef, useState } from 'react'

export default function usePush(): NextRouter['push'] {
    const router = useRouter()
    const routerRef = useRef(router)

    routerRef.current = router

    const [{ push }] = useState<Pick<NextRouter, 'push'>>({
        push: path => routerRef.current.push(path),
    })
    return push
}

它返回一个语义记忆的推送函数,因此可以安全地与 useEffect 一起使用,例如

const push = usePush()

useEffect(() => {
    checkLoggedIn().then(loggedIn => {
        if (!loggedIn) {
            push('/login')
        }
    })
}, [push])

【讨论】:

    【解决方案2】:

    @mledezma 提出的解决方法效果很好,如果你还不能理解 TS,这是一个 JS 重构:

    import { useRef, useState } from "react";
    import { useRouter } from "next/router";
    
    export const usePush = () => {
      const router = useRouter();
      const routerRef = useRef(router);
      routerRef.current = router;
      const [routerPush] = useState(() => {
        const push = (path) => {
          routerRef.current.push(path);
        };
        return push;
      });
    
      return routerPush;
    };
    

    【讨论】:

      猜你喜欢
      • 2022-09-30
      • 2020-04-08
      • 1970-01-01
      • 2021-07-07
      • 2021-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-24
      相关资源
      最近更新 更多