dans mon application react, j'ai 3 composants. à partir du 1er composant par un bouton, j'utilise Link pour aller au 2ème composant. au 2ème je crée un état (redux store), le manipule et quand la manipulation est terminée en soumettant le bouton je redirige vers le 3ème composant. au 3ème composant, je vois aussi l'état (par redux chrome) mais ici quand je rafraîchis la page (le truc webpack quand un code est changé et sauvegardé), je perds l'état et récupérez un objet vide.
c'est la structure de mon application.
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;
Ici à HomePage, j'ai un bouton qui relie à GameInit
const HomePage = () => (<Button color="blue" as={Link} to="/GameInit">START GAME</Button>);
export default HomePage;
et la page GameInit ressemble
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);
et enfin le composant Battle où je vois l'état pour la première fois mais je perds au rafraîchissement
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);
Vous pouvez facilement le conserver dans le stockage local. Consultez l'exemple ci-dessous.
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');
);
La sérialisation est une opération coûteuse. Vous devez utiliser une fonction de limitation (comme celle implémentée par lodash
) pour limiter le nombre de sauvegardes.
Par exemple:
import throttle from 'lodash/throttle';
store.subscribe(throttle(() => {
saveState(store.getState());
}, 1000));
Vous pouvez utiliser quelque chose comme redux-persist pour enregistrer l'état de redux dans local storage
ou vers un autre système de stockage.
Mon conseil personnel pour le rechargement à chaud est d'utiliser ceci: React hot loader , cela empêche le rechargement de la page et ne change que le morceau modifié. Cela implique que votre état ne se perd jamais pendant le développement.
C'est assez facile à installer. Vous n'avez qu'à ajouter une entrée et à envelopper votre composant initial dans hot
que vous pouvez obtenir à partir du package.
Si vous avez besoin de plus d'informations sur son fonctionnement, je vous suggère de regarder cet exposé par le créateur.
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);
}