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 需要编写大量代码。
在我的 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 需要编写大量代码。