带有 useEffect 的 Next.js useRouter 即使在页面刷新时满足条件也会推送

Posted

技术标签:

【中文标题】带有 useEffect 的 Next.js useRouter 即使在页面刷新时满足条件也会推送【英文标题】:Next.js useRouter with useEffect pushes even if condition is met on page refresh 【发布时间】:2021-12-31 16:00:20 【问题描述】:

我遇到了useRouteruseEffect 的问题,如果不满足某个条件,我想重定向用户。

在第 1 页上,您选择一个 amount,该amount 被传递到上下文中并在第 2 页上被检索。

在第 2 页我有这种情况:

import  useEffect, useContext  from "react";
import  useRouter  from "next/router";
import AppContext from "../context/AppContext";

const PageTwo = () => 
  const  amount  = useContext(AppContext);
  const router = useRouter();
  useEffect(() => 
    if (!amount || amount == null) 
      router.push("/page-1"); // redirect if no amount is selected
    
  );

  return (
    ...
  );
;

当我们到达第 2 页时,我有 amount,但是当您刷新页面时,即使设置了 amount,它也会将您引导回 page-1。当您直接转到page-2 时,它工作正常,而不在page-1 上选择金额,它会将您重定向回page-2

在这种情况下,上下文 API 和/或 useRouter 和 useEffect 的工作方式可能有问题。

这是一个有问题的 CodeSanBox 示例:

https://codesandbox.io/s/next-js-userouter-with-useeffect-6645u?file=/pages/page-2.js

【问题讨论】:

如果您在“AppContext”中保持“amount”状态并且用户进行页面刷新,“amount”状态将是它的默认值。你确定吗? “当您刷新页面时,即使设置了数量,它也会将您引导回第 1 页。” 没错。即使设置了amount,在page-2 上的页面刷新时,它也会直接返回page-1。当控制台记录数量时,您可以看到它在那里。也许我会设置一个快速的 CodeSandBox 来详细说明自己。 你得到未定义的瞬间导致重定向回第 1 页。 这很奇怪,因为在设置数量时,它也被存储在 localStorage 中。关于如何解决这个问题的任何想法?也许有更好的方法来处理这个问题。 【参考方案1】:

clearAmount 函数和_app 文件中的useState("") 中将null 更改为空字符串("") 而不是(null)。此外,将您的 if 语句更改为 if (amount === "")。解决了它,这是我从你的沙箱中分叉出来的。 https://codesandbox.io/s/next-js-userouter-with-useeffect-forked-t2enf?file=/pages/page-2.js

【讨论】:

我想我们快到了。问题是,在“新”页面访问中,您仍然可以直接访问page-2 并停留在page-2 上并显示:The amount is: null。相反,它也应该重定向回page-1 在 _app.useState("") 中添加相同的空字符串。我更新了答案.. 我讨厌成为坏消息的带来者,但现在当您在page-1 上选择金额时,然后在page-2 上刷新页面。它会将您重定向回page-1【参考方案2】:

出现这种情况是因为即使在上下文中设置了新的amount 值后,在重新加载页面时,它的初始值在第一次渲染时将是null,这发生在应用程序检查并设置localStorage 值之前。这会触发重定向setAmount(amount) 使用来自localStorage 的存储值调用。

为了通过最小的更改来防止这种情况,您可以修改触发重定向到以下内容的检查。确保还将amount 添加到useEffect 的依赖项数组中。

useEffect(() => 
    if (amount === "") 
        router.push("/page-1");
    
, [amount]);

如果未存储任何值,您还必须将传递给 setAmount 中的 _app 的值更改为默认为空字符串。

useEffect(() => 
    const amount = localStorage.getItem("amount") ?? "";
    setAmount(amount);
, []);

这允许我们为初始状态值 (null) 和空值 ("") 设置不同的值。这意味着在使用存储在localStorage 中的值更新amount 之前不会发生重定向。

最后,为了保持逻辑一致,您必须更新clearAmount 函数,将amount 设置为空值。

const clearAmount = () => 
    setAmount("");
;

【讨论】:

以上是关于带有 useEffect 的 Next.js useRouter 即使在页面刷新时满足条件也会推送的主要内容,如果未能解决你的问题,请参考以下文章

Next js 应用刷新时,useEffect 不调度 redux saga 动作并更新状态

如何在头组件中使用效果(ReactJS/Next.js)

使用 useEffect 与 onAuthStateChanged 检测 Firebase 用户更改 - 有啥区别?

无法导出带有 getServerSideProps 的 nextjs 页面

Next.js 重定向/验证

在 useEffect 内部或外部定义函数?