React Redux 状态在页面刷新时丢失

Posted

技术标签:

【中文标题】React Redux 状态在页面刷新时丢失【英文标题】:React Redux state is lost at page refresh 【发布时间】:2019-02-09 04:22:41 【问题描述】:

在我的反应应用程序中,我有 3 个组件。通过一个按钮从第一个组件,我使用链接转到第二个组件。在第 2 次我创建一个状态(redux 存储),对其进行操作,当通过提交按钮完成操作时,我重定向到第 3 个组件。在第三个组件,我也看到了状态(通过 redux chrome 工具),但是当我刷新页面时(更改和保存代码时的 webpack 事情),我失去了状态并得到一个空对象。

这是我的应用程序的结构。

index.js

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(thunk))
);

ReactDOM.render(
  <BrowserRouter>
    <Provider store=store>
      <Route component=App />
    </Provider>
  </BrowserRouter>,
  document.getElementById("root")
);

App.js

const App = ( location ) => (
  <Container>
    <Route location=location path="/" exact component=HomePage />
    <Route location=location path="/GameInit" exact component=GameInit />
    <Route location=location path="/Battle" exact component=Battle />
  </Container>
);

App.propTypes = 
  location: PropTypes.shape(
    pathname: PropTypes.string.isRequired
  ).isRequired
;

export default App;

在主页,我有一个链接到 GameInit 的按钮

const HomePage = () => (<Button color="blue" as=Link to="/GameInit">START GAME</Button>);
export default HomePage;

GameInit 页面看起来像

class GameInit extends Component 
  componentWillMount() 
    const  createNewPlayer = this.props;
    createNewPlayer();
  
/* state manipulation till it gets valid */
 palyerIsReady()=> history.push("/Battle");

export default connect(mapStateToProps, createNewPlayer)(GameInit);

最后是我第一次看到状态但在刷新时丢失的战斗组件

class Battle extends Component 
  render() return (/*some stuff*/);

Battle.propTypes = 
  players: PropTypes.object.isRequired // eslint-disable-line
;
const mapStateToProps = state => (
  players: state.players
);
export default connect(mapStateToProps,null)(Battle);

【问题讨论】:

这很自然... @BhojendraRauniyar 和解决方案? 这里不是 Thunk 作为中间件来处理这个问题吗?如果我想将所有内容持久化到本地存储中,为什么还要使用 redux? 否则你可以使用 redux-persist 准备初始状态并通过 createStore(combined, a: 'horse' ) 传递它。 redux.js.org/recipes/structuringreducers/initializingstate。从我的角度来看,这是原因 【参考方案1】:

您可以使用redux-persist 之类的东西将redux 状态保存到local storage 或 到另一个存储系统。

【讨论】:

【参考方案2】:

您可以轻松地将其保存在本地存储中。检查下面的示例。

const loadState = () => 
  try 
    const serializedState = localStorage.getItem('state');
    if(serializedState === null) 
      return undefined;
    
    return JSON.parse(serializedState);
   catch (e) 
    return undefined;
  
;

const saveState = (state) => 
  try 
    const serializedState = JSON.stringify(state);
    localStorage.setItem('state', serializedState);
   catch (e) 
    // Ignore write errors;
  
;

const peristedState = loadState();

store.subscribe(() => 
  saveState(store.getState());
);

const store = createStore(
  persistedState,
  // Others reducers...
);

render(
  <Provider store=store>
    <App/>
  </Provider>,
  document.getElementById('root');
);

序列化是一项昂贵的操作。您应该使用限制功能(如 lodash 实现的功能)来限制保存次数。

例如:

import throttle from 'lodash/throttle';

store.subscribe(throttle(() => 
  saveState(store.getState());
, 1000));

【讨论】:

这看起来很有说服力。所以不再需要 thunk 了吗? 为了查看 chrome 扩展时的状态,我应该写 composeWithDevTools(persistedState) ? 它不会改变您现有代码的任何内容。 createStore 的第二个参数只是初始状态。您仍然可以添加 thunk 并插入 chrome 扩展。 啊哈,我明白了,非常感谢。我的情况的最佳解决方案:) @Temi'Topsy'Bello 我认为代码有错误,你应该在store声明之后写store.subscribe(...)【参考方案3】:

我个人对热重载的建议是使用这个:React hot loader,这可以防止页面重载并且只切换出改变的块。这意味着您的状态在开发时永远不会丢失。

它很容易安装。您只需添加一个条目并将您的初始组件包装在 hot 中,您可以从包中获取它。

如果您需要有关其工作原理的更多信息,我建议您观看创作者的this talk。

【讨论】:

【参考方案4】:
    import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
import  Provider  from "react-redux";
import  store  from "./rootReducer";
import  BrowserRouter  from "react-router-dom";

if (process.env.NODE_ENV === "development" && module.hot) 
  module.hot.accept("./rootReducer", () => 
    const newRootReducer = require("./rootReducer").default;
    store.replaceReducer(newRootReducer);
  );


export type AppDispatch = typeof store.dispatch;

const render = () => 
  const App = require("./App").default;
  ReactDOM.render(
    <Provider store=store>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>,
    document.getElementById("root"),
  );
;

render();

if (process.env.NODE_ENV === "development" && module.hot) 
  module.hot.accept("./App", render);

【讨论】:

【参考方案5】:

Alexender Annic 正确回答:

// persist store code
const loadState = () => 
  try 
    const serializedState = localStorage.getItem('state');
    if(serializedState === null) 
      return undefined;
    
    return JSON.parse(serializedState);
   catch (e) 
    return undefined;
  
;

const saveState = (state) => 
  try 
    const serializedState = JSON.stringify(state);
    localStorage.setItem('state', serializedState);
   catch (e) 
    // Ignore write errors;
  
;

const persistedState = loadState();

// This persistedState is includedat the time of store creation as initial value
const store = createStore(reducers, persistedState);

// This is actually call every time when store saved
store.subscribe(() => 
  saveState(store.getState());
);


export default store;

【讨论】:

以上是关于React Redux 状态在页面刷新时丢失的主要内容,如果未能解决你的问题,请参考以下文章

如何保存切换状态,刷新页面后不会丢失

如何在 react-redux 中调用页面刷新的函数?

React s-s-r路由器-导航到子路由时的redux状态丢失

React Redux 刷新问题

页面刷新后 React useReducer 钩子状态丢失

在 react redux 应用程序中手动导航时状态丢失