31

For example...

export const user = (state = {
  id: localStorage.getItem('id'),
  name: localStorage.getItem('name'),
  loggedInAt: null
}, action) => {
    case types.LOGIN:
      localStorage.setItem('name', action.payload.user.name);
      localStorage.setItem('id', action.payload.user.id);
      return { ...state, ...action.payload.user }

    default:
      return {  ...state, loggedInAt: Date.now() }
}

That's a scaled down version of what I'm doing, default returns the state from localStorage as expected. However the state of my application is actually blank once I refresh the page.

Ewan Valentine
  • 3,741
  • 7
  • 43
  • 68

1 Answers1

47

Redux createStore 2nd param is intended for store initialization:

createStore(reducer, [initialState], [enhancer])

So you can do something like this:

const initialState = {
  id: localStorage.getItem('id'),
  name: localStorage.getItem('name'),
  loggedInAt: null
};

const store = createStore(mainReducer, initialState);

Since reducers should be pure functions (i.e. no side effects) and localStorage.setItem is a side effect, you should avoid saving to localStorage in a reducer.

Instead you can:

store.subscribe(() => {
    const { id, name } = store.getState();

    localStorage.setItem('name', name);
    localStorage.setItem('id', id);
});

This will happen whenever the state changes, so it might affect performance.

Another option is to save the state only when the page is closed (refresh counts) using onBeforeUnload:

window.onbeforeunload = () => {
    const { id, name } = store.getState();

    localStorage.setItem('name', name);
    localStorage.setItem('id', id);
};
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • And yet another option is to use something like pouchDB and couchDB with middleware to help keep the store stateless. – ZekeDroid Apr 12 '16 at 19:43
  • what about writing to localstorage in the action creators? they are allowed to have side effects. also, is reading via `localstorage.getItem` to load initial state in the reducer parameter as OP describes a side effect? – user210757 Jun 25 '19 at 21:51
  • You can use localStorage in action creators for granular state saves. Although I would still prefer a central save state that I can tune. Reducer should be pure functions, and adding data from localStorage in the body of the function is a side effect. – Ori Drori Jun 26 '19 at 07:31