8

I'm working on my first react/redux app and I'm not sure where I should call sessionStorage.setItem(). I'm currently storing user credentials from a loginUserSuccess() action but I'm not sure this is where I should be doing that. Furthermore, I'm using fetch to make requests and would like to add the user's authToken to all requests. I was looking into fetch-intercept but not much documentation is provided for modifying headers.

actions/loginActions.js

export function loginUser(user) {
  return function(dispatch) {
    return LoginApi.login(user).then(creds => {
      dispatch(loginUserSuccess(creds));
    }).catch(error => {
      throw(error);
    });
  };
}

export function loginUserSuccess(creds) {
  sessionStorage.setItem('credentials', JSON.stringify(creds));
  return {
    type: types.LOGIN_USER_SUCCESS,
    state: creds
  }
}

api/packageApi.js

class PackageApi {
  // called on successful login
  static getAllPackages() {
    const request = new Request('/my/endpoint', {
      method: 'GET',
      headers: new Headers({
        'AUTHORIZATION': `Bearer ${JSON.parse(sessionStorage.credentials).authToken}`
      })
    });
    return fetch(request).then(response => {
      return response.json();
    }).catch(error => {
      return error;
    });
  }
}

export default PackageApi;
neridaj
  • 2,143
  • 9
  • 31
  • 62
  • Possible duplicate of [Where to write to localStorage in a Redux app?](https://stackoverflow.com/questions/35305661/where-to-write-to-localstorage-in-a-redux-app) – Jim G. Jul 05 '18 at 11:48

2 Answers2

9

Taking into consideration Dan Abramov's explanation we have the following:

store/sessionStorage.js

export const loadState = () => {
  try {
    const serializedState = sessionStorage.getItem('state');

    if (serializedState === null) {
      return undefined;
    }

    return JSON.parse(serializedState);
  } catch (error) {
    return undefined;
  }
};

export const saveState = (state) => {
  try {
    const serializedState = JSON.stringify(state);
    sessionStorage.setItem('state', serializedState);
  } catch (error) {
    // Ignore write errors.
  }
};

store/index.js

import { createStore } from 'redux';
import rootReducer from '../reducers';
import { loadState, saveState } from './sessionStorage';

const persistedState = loadState();
const store = createStore(rootReducer, persistedState);

store.subscribe(() => {
  saveState(store.getState());
});

Full explanation: https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage

Ronald Araújo
  • 1,395
  • 4
  • 19
  • 30
  • For [Redux Toolkit](https://redux-toolkit.js.org)'s [`configureStore`](https://redux-toolkit.js.org/api/configureStore) instead of `createStore` line just pass `persistedState` value into `preloadedState` option of `ConfigureStoreOptions` object like this: `const store = configureStore({preloadedState: loadState(), reducer: ...})`. – holem Dec 22 '22 at 08:39
2

Think about a sessionStorage as just one more store. This store needs to be synced with the Redux one so it works properly. I think the reducer is the right place. That is where you have data changes and data initialization.

Krasimir
  • 13,306
  • 3
  • 40
  • 55