【问题标题】:React JS page keeps refreshing when using the back button使用后退按钮时 React JS 页面不断刷新
【发布时间】:2021-04-28 21:55:00
【问题描述】:

我有 2 个 React JS 页面(A 和 B),当我从 A->B 转到 A 时,每次都会刷新页面 A。我的印象是页面没有被破坏。 StackOverflow 上的所有相关问题似乎都与相反的问题有关。

页面刷新的原因是尽管使用了 useState() 来防止这种情况,但在按下后退按钮时调用了 useEffect()。我什至尝试用“props.id”参数替换“刷新”(永远不会改变)。见以下代码:

这是我到页面 A 的代码:

import { useHistory, useParams } from "react-router-dom";
import React, { useState, useEffect, useRef } from "react";
import { Link } from "react-router-dom";

export default function Test(props) {
    const [refresh, setRefresh] = useState(false);
    
    useEffect(() => {
        console.log("useEffect called: "+refresh);
        setRefresh(true);
    },[refresh]);

    return (
        <>
            Hello from Test
            <Link to="/test2">Test me</Link>
        </>
    );
}

我正在使用 react-router-dom: "^5.1.2",并从 "react-router-dom" 导入 { BrowserRouter as Router };在 App.js 中并指定:

  <Switch>
      <Route exact path="/">
        <Home />
      </Route>
          <Route exact path="/test">
        <Test id="1"/>
      </Route>
      <Route exact path="/test2">
        <Test2 />
      </Route>
      .....

有谁知道如何防止在返回页面时触发 useEffect() ?实际页面 A 使用 REST 调用获取并显示一长串项目,我不希望每次用户加载页面 B 以查看项目然后返回页面时刷新页面。

【问题讨论】:

    标签: reactjs react-router-dom


    【解决方案1】:

    你需要给useEffect添加一个条件。 如果您只想将 setRefresh 设置为 true(如果为 false),请执行以下操作:

    useEffect(() => {
      if(!refresh) setRefresh(true)
    }, [refresh])
    

    由于您从 const [refresh, setRefresh] = useState(false) 开始并且没有更改组件中其他任何地方的刷新,因此每次加载(而不是渲染)组件时都会运行一次。

    如果您想在应用程序的生命周期而不是组件的生命周期中运行一次,您需要将信息保存在组件之外,方法是将状态提升到父组件并保存信息,例如 @987654323 @/sessionstorage.

    然后,您可以在组件加载时提取此信息,并相应地设置 refresh 状态变量。

    假设您只想将 setRefresh 设置为 true 一次。添加这个useEffect:

    useEffect(() => {
      let persistedRefresh
      try {
        persistedRefresh = !!JSON.parse(window.localstorage.getItem('THE_KEY_TO_REFRESH_VALUE'))
      } catch(error) {
        persistedRefresh = false  
      }
      setRefresh(persistedRefresh)
    }, [])
    

    这个 useEffect 将在组件加载时运行,并更新状态变量,触发之前的 useEffect。

    我们还需要修改之前的useEffect:

    useEffect(() => {
      if(!refresh) { 
        setRefresh(true)
        window.localstorage.setItem('THE_KEY_TO_REFRESH_VALUE', JSON.stringify(true))
      }
    }, [refresh])
    

    在这个useEffect 中,我们正在更新持久化的值,以便每当组件加载时,

    • 它将检查持久化的值,
    • 根据需要刷新,并且
    • 为下一次加载更新持久值。

    这就是您在没有任何额外依赖项的情况下执行此操作的方式。

    【讨论】:

      【解决方案2】:

      解决方案 1(正确方法)

      使用无状态组件并拥有一个通用的超级状态(Redux 将有很大帮助),并将您的页面/数据绑定到通用状态,因此即使状态发生变化,页面也会始终呈现当前状态,从而产生页面错觉保留状态(我用它来运行大型查询并将进度/结果存储在 redux 中,所以即使我打开另一个页面并返回,我也会看到查询正在进行或结果)。

      但是我不确定你的用例是什么。

      解决方案 2(略有错误)

      使用React.memo,当你不想更新你认为是静态的组件时可以使用它

      对于功能组件:

       const Mycomponents = React.memo(props => {   
            return <div> 
                       No updates on this component when rendering,  use useEffect to verify too 
                  </div>;
       });
      

      您不应该在这种方法中定义任何方法/功能/动态计算,以避免获取不规则数据

      【讨论】:

        【解决方案3】:

        我可以看到您正在导入非常有用的 useHistory 道具,但没有做太多。它实际上可用于检查用户是否使用后退按钮导航到页面。 useHistory() 的行动会告诉你你需要的一切。如果使用后退按钮,action 将是“POP”。因此,您可以在 useEffect 中添加一些逻辑来检查:

          const history = useHistory();
          React.useEffect(() => {
            if (history.action === "POP")
              console.log("Back button used. Not running stuff");
            else console.log("useEffect called in home");
          }, []);
        

        这是Sanbox。在这里,您可以在专用浏览器窗口中实际测试沙盒代码:https://okqj3.csb.app/

        单击“关于”链接,然后使用返回按钮返回“主页”,在控制台中您将看到 Home 元素的 useEffect 函数如何捕获它。

        【讨论】:

        • 感谢您的回答。我实际上已经尝试过,并注意到 history.action 总是等于“POP”,即使我第一次加载页面也是如此。这可以解释为什么我会遇到这个问题。我注意到控制台中有一条警告:“ 忽略历史记录。要使用自定义历史记录,请使用 import { Router } 而不是 import { BrowserRouter as Router }。”这可能是问题吗?
        • 当我测试您的沙箱okqj3.csb.app 时,我得到了相同的效果,即第一次加载页面时,它显示“已使用后退按钮”。不运行东西;' (在 Chrome 和 Safari 中都处于隐身模式)
        • @jvence 你是对的。它也是第一次加载时的 POP。当你从另一个页面返回时它会变成 PUSH,但是是的,当你第一次加载页面时应该有一些东西可以捕捉到它。我稍后会检查一下。感谢您的提醒。
        • 不会转push,除非你使用Link进入第1页,如果你使用浏览器上的后退按钮,它仍然是一个POP。
        猜你喜欢
        • 1970-01-01
        • 2011-02-13
        • 2018-09-30
        • 1970-01-01
        • 2022-09-23
        • 1970-01-01
        • 2012-03-02
        • 2014-01-20
        • 1970-01-01
        相关资源
        最近更新 更多