在反应中丢失页面刷新时的组件数据

Posted

技术标签:

【中文标题】在反应中丢失页面刷新时的组件数据【英文标题】:Loosing component data on page refresh in react 【发布时间】:2020-10-10 16:56:05 【问题描述】:

我正在做一些我需要维护应用程序级别状态的事情,即全局状态,我正在为 useContextuseReducer 使用反应钩子。

所以我正在做的是点击按钮,我正在设置我的上下文,然后通过在我的App.js 中注册提供程序来使用它认为我的应用程序。

我知道我为什么要使用我的数据,因为我首先将初始状态设置为 null,这就是为什么当我刷新页面时它再次设置为 null,但我的要求不是在单击按钮后我想存储它数据作为全局状态,以便我可以进一步使用它

但这不应该是我想让我的数据全局化并且刷新时它不应该丢失的情况

我的代码

我的上下文文件

import React,  useReducer, createContext  from "react";

const initialstate = 
  someData: null
;

const MyContext = createContext(
  someData: null,
  click_btn: d => 
);
const MyReducer = (state, action) => 
  switch (action.type) 
    case "BTNCLICKED":
      return 
        ...state,
        someData: action.payload
      ;

    default:
      return state;
  
;

const MyProvider = props => 
  const [state, dispatch] = useReducer(MyReducer, initialstate);
  const click_btn = d => 
    dispatch(
      type: "BTNCLICKED",
      payload: d
    );
  ;

  return (
    <MyContext.Provider
      value= someData: state.someData, click_btn 
      ...props
    />
  );
;

export  MyContext, MyProvider ;

我设置上下文的主代码

    import React,  useContext, useState  from "react";
import history from "../History/history";

import  MyContext  from "../context/testContext";

function Test() 
  const context = useContext(MyContext);
  const [data, setdata] = useState(null);
  const clickEvt = () => 
    setdata("Setting data");
    context.click_btn(data);
  ;
  return (
    <div>
      <input type="button" onClick=clickEvt value="Click Me" />
    </div>
  );


export default Test;

还有我的 app.js 文件

    import React from "react";
import "./styles.css";
import  MyProvider  from "./context/testContext";
import  Router  from "react-router-dom";
import history from "./History/history";
import Routes from "./myRoutes";

export default () => 
  return (
    <MyProvider>
      <Router history=history>
        <div className="App wrapper">
          <Routes />
        </div>
      </Router>
    </MyProvider>
  );
;

请检查工作代码My codesand box link

请检查 react 开发者工具

【问题讨论】:

【参考方案1】:

要持久化 React 上下文、redux 存储或任何存在于应用内存中的内容,您需要将其存储在外部,然后在应用启动时重新加载(当您按下 F5 时,页面会刷新,您的 React 应用重新启动,因此它会丢失所有组件状态、上下文、存储...)。

例如,您可以将上下文保存在本地存储中,然后修改上下文,使其首先搜索存储的值并首先重新加载它。可以在您的上下文中使用 useEffect 来完成:每次更改时,将其存储在本地存储中,并在启动时预加载本地存储值:

// context
[...]

useEffect(() => 
  if(localStorage.getItem('myKey')) 
    setState(localStorage.getItem('myKey');
  
, []);

useEffect(() => 
  localStorage.setItem('myKey', state);
, [state]);

大致是这样的,可以用重构。

您还可以选择将上下文保存在远程服务器或本地 noSQL DB 上。你会发现很多解决方案:

https://medium.com/@akrush95/global-cached-state-in-react-using-hooks-context-and-local-storage-166eacf8ab46 https://github.com/aprilmintacpineda/react-context-api-store https://www.robinwieruch.de/local-storage-react https://dev.to/selbekk/persisting-your-react-state-in-9-lines-of-code-9go ...

【讨论】:

如果我可以存储在本地存储中,那么我需要创建一个全局状态,我可以轻松地将数据存储在本地存储中,然后我可以从那里获取 Context API 让您可以轻松地从所有组件的全局状态中检索数据,并可能添加一些逻辑。但是,是的,两者都允许您存储全局状态,并且一个在页面刷新时仍然存在。 引用您的其他评论:“仅在 React 中维护状态”可以在页面刷新后存活,没有本地存储,没有外部数据库,这是一个艰难的 :)。这是 react-redux 的持久化包,但问题和解决方案是相似的,所以你可以找到灵感:github.com/rt2zz/redux-persist#storage-engines【参考方案2】:

来自您的评论

本地存储不是一个好选择我不想把这个值 那里任何人都可以删除它们,我想保持状态 只反应

在这种情况下, LocalStorage 是客户端,react 是一个框架,也是客户端。客户端中的任何内容都可以以任何方式进行编辑。您不能在假设恶意意图的情况下依赖客户端的数据。如果 React 可以获取或编辑某些内容,任何具有 JS 知识的人都可以对其进行编辑。

您唯一可以信任的是您的后端服务器。客户端发送用户想要做的事情,服务器验证它然后处理请求,将结果发送回客户端。

您可以搜索此关键字以获取更多详细信息。

client server prevent cheat

【讨论】:

必须信任的敏感信息必须经过后端服务器,但并非所有值都需要是信任值。任何来自客户端的值,包括令牌,无论如何都可以被操纵。你的回答也有道理。然而,即使提问者真正想要的答案似乎不会丢失,即使他或她在客户端刷新。 因此,我认为没有必要将所有不影响服务的值都存储到服务器,即使这些值被操纵。 假设 OP 了解敏感和非信息,并且仍然拒绝将任何数据放入 localStorage,那么反应状态也不是他的选择。 localStorage 或 react state 的安全级别,几乎是一样的。如果能够操作 localStorage,react state 也很容易被操作,这是 OP 想要阻止的。【参考方案3】:

缺少持久性机制。您可以扩展 MyProvider 函数,以便它从 localStorage 或 api 获取值

API 示例


const MyProvider = props => 
  const [state, dispatch] = useReducer(MyReducer, initialstate);
  const click_btn = payload => 
    saveStateToApi(payload)
      .then(result => 
         dispatch(
           type: "BTNCLICKED",
           payload
         );
      )
  ;

  useEffect(() => 
    getLastStateFromApi()
      .then(data => 
        dispatch(
          type: "BTNCLICKED",
          payload: data
        );
      )

  , [])

  return (
    <MyContext.Provider
      value= someData: state.someData, click_btn 
      ...props
    />
  );
;

【讨论】:

嘿,本地存储不是一个好选择刷新时数据丢失,但为此我编写了一个 api,它给了我当前的 api,但是对于这个,我不能向后端写任何查询 这不像你有很多选择。随着页面刷新,您将失去整个反应状态,因为必须获取 html 并再次引导反应,您可以使用(如果支持)浏览器持久性机制,如 localStoragesessionStorageindexedDb 或外部 api . 来自 redux-persist 的灵感:github.com/rt2zz/redux-persist#storage-engines

以上是关于在反应中丢失页面刷新时的组件数据的主要内容,如果未能解决你的问题,请参考以下文章

vue: 解决vuex页面刷新数据丢失问题

解决vuex刷新页面数据丢失

vue路由传参页面刷新参数丢失问题解决方案

解决vuex在页面刷新后数据丢失的问题

Vue 路由跳转传递参数,子组件页面刷新后数据不丢失

React 路由组件选择与页面刷新问题分析