10

in my react app I have 3 components. from the 1st component by a button, I use Link to go to the 2nd component. at the 2nd I create a state (redux store), manipulate it and when manipulation is finished by submitting button I redirect to the 3rd component. at the 3rd component, I also see the state (by redux chrome tool) but here when I refresh the page (the webpack thing when a code is changed and saved), I lose the sate and get an empty Object.

this is the structure of my app.

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;

Here at HomePage, I have a button that links to GameInit

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

and the GameInit Page looks like

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

and finally Battle component where I first see the state but lose on refresh

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);
Amir-Mousavi
  • 3,249
  • 4
  • 40
  • 86

5 Answers5

22

You can easily persist it in the localstorage. Check the example below.

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

Serialization is an expensive operation. You should use a throttle function (like the one implemented by lodash) to limit the number of saves.

Eg:

import throttle from 'lodash/throttle';

store.subscribe(throttle(() => {
  saveState(store.getState());
}, 1000));
Alexandre Annic
  • 7,089
  • 3
  • 28
  • 40
4

You can use something like redux-persist to save the redux state to local storage or to another storage system.

illiteratewriter
  • 3,204
  • 1
  • 16
  • 35
1

My personal advice for hot reloading is using this: React hot loader, this prevents page reload and only switch out the altered chunk. This implies that your state never gets lost while devving.

It is pretty easy to install. You only have to add an entry and wrap your initial component in hot which you can get from the package.

If you need more information on how it works i suggest watching this talk by the creator.

jovi De Croock
  • 517
  • 2
  • 8
0
    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);
}
0

Alexender Annic Answer in correct way:

// 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;
Hassan Ali Shahzad
  • 1,875
  • 18
  • 26