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

React Redux state is lost at page refresh

在我的 React 应用程序中,我有 3 个组件。从第一个组件按一个按钮,我使用 Link 转到第二个组件。第二次我创建了一个状态(redux store),对其进行操作,当通过提交按钮完成操作时,我重定向到第三个组件。在第三个组件,我也看到了状态(通过 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);

最后是 Battle 组件,我第一次看到状态但在刷新时丢失了

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);

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

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

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));

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

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

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

    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);
}

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;

每个人都在推荐 localStorage,但您也可以只保存到 sessionStorage(我读过它比 localStorage 更安全)并在刷新时检查存储项目。 您可以在响应成功或任何地方设置它。

window.sessionStorage.setItem("sessionName",JSON.stringify(message.payload));

然后可以check in你的componentDidUpdate或者mount。

  if(!isLoggedIn && !isAuthenticated && window.sessionStorage.getItem('session-name')){
            saveWhatYouWant(JSON.parse(window.sessionStorage.getItem('sessionName')))
        
        }

我发现这工作得更快,你实际上是在重新填充商店 w/out 需要编写大量代码。