Redux state persistence with a database

23,698

Solution 1

From the discussion here it seems that the state of Redux reducers should be persisted in a database.

To persist the state or not, it's likely not a concern of Redux at all. It's more up to application logic.

If something happens in an application, like data upload to server, obviously you need to save state (or a slice of the state to a server).

Since network calls are asynchronous, but Redux is synchronous - you need to introduce additional middleware, as redux-thunk or redux-promise.

As sign-up example, you likely need that actions,

export function creatingAccount() {
  return { type: 'CREATING_ACCOUNT' };
}

export function accountCreated(account) {
  return { type: 'ACCOUNT_CREATED', payload: account };
}

export function accountCreatingFailed(error) {
  return { type: 'ACCOUNT_CREATING_FAILED', payload: error };
}

export function createAccount(data, redirectParam) {
  return (dispatch) => {
    dispatch(creatingAccount());

    const url = config.apiUrl + '/auth/signup';

    fetch(url).post({ body: data })
      .then(account => {
        dispatch(accountCreated(account));
      })
      .catch(err => {
        dispatch(accountCreatingFailed(err));
      });
  };
}

Some portion of state, e.g. user object after authorization, might be stored to localStore and re-hydrated on next application run.

Solution 2

Those are valid concerns. Using localStorage to persist state on the frontend might be a better strategy. You can implement this using middleware, for example:

import {createStore, compose, applyMiddleware} from 'redux';

const localStorageMiddleware = ({getState}) => {
  return (next) => (action) => {
    const result = next(action);
    localStorage.setItem('applicationState', JSON.stringify(
      getState()
    ));
    return result;
  };
};

const store = compose(
  applyMiddleware(
    localStorageMiddleware
  )
)(createStore)(
  reducer,
  JSON.parse(localStorage.getItem('applicationState'))
)

If you're concerned about the enemy accessing the user's laptop and stealing credentials from it you could persist state to the backend when the user leaves the page (Navigator.sendBeacon() might be helpful here) & store it in the session.

Share:
23,698
hoodsy
Author by

hoodsy

Updated on July 05, 2022

Comments

  • hoodsy
    hoodsy almost 2 years

    From the discussion here it seems that the state of Redux reducers should be persisted in a database.

    How does something like user authentication works in this instance?

    Wouldn't a new state object be created to replace the previous state in the database for every user (and their application state) created and edited?

    Would using all of this data on the front end and constantly updating the state in the database be performant?

    Edit: I've created an example Redux auth project that also happens to exemplify universal Redux, and realtime updating with Redux, Socket.io and RethinkDB.

  • hoodsy
    hoodsy over 8 years
    This helps immensely - thank you for the articulate response!
  • hoodsy
    hoodsy over 8 years
    Thanks for the clarification. Would it make sense to store user credentials in the database?
  • Ashton Six
    Ashton Six over 8 years
    Absolutely! You'd still want to store information on the backend, localStorage is transient and you shouldn't assume data will last more than 30 days there. The use cases for localStorage include storing auth tokens, the current page, data loaded from the backend (to avoid reloads). Redux state contains a lot of these which is why rehydrating it between page loads makes sense. Storing data on the backend is often nescersary, sometimes a different approach makes more sense.
  • Jordan
    Jordan over 8 years
    local storage should never be used for storing authentication information as it is very vulnerable to XSS attacks => local storage is not domain-specific so an attacker doesn't even have to inject a script into your site to access it - they can simply get an unwitting victim to go to {$someEvilDomain}.com and then run a script from there that grabs everything in local storage
  • Ashton Six
    Ashton Six over 8 years
    @Martin Oversight on my part regarding XSS vulnerability. But how would you access cross-domain localStorage?
  • Jordan
    Jordan over 8 years
    @AshtonWar - actually my recollection was incorrect - you can't enumerate all keys across all domains, but you can target specific domains via some iFrame sourcery, but bottom line is storing authentication data in local storage (or any sensitive information) is generally frowned upon by security folks
  • Jordan
    Jordan over 8 years
    Also worth noting that some folks try to get around this limitation by storing auth data on the client in an encrypted form, but I can tell you from personal experience that this probably won't survive a security audit