Redux: Opinions/examples of how to do backend persistence?

Definitely persist the state of your reducers!

If you persisted a sequence of actions instead, you wouldn’t ever be able to modify your actions in your frontend without fiddling around inside your prod database.

Example: persist one reducer’s state to a server

We’ll start with three extra action types:

// actions: 'SAVE', 'SAVE_SUCCESS', 'SAVE_ERROR'

I use redux-thunk to do async server calls: it means that one action creator function can dispatch extra actions and inspect the current state.

The save action creator dispatches one action immediately (so that you can show a spinner, or disable a ‘save’ button in your UI). It then dispatches SAVE_SUCCESS or a SAVE_ERROR actions once the POST request has finished.

var actionCreators = {
  save: () => {
    return (dispatch, getState) => {
      var currentState = getState();
      var interestingBits = extractInterestingBitsFromState(currentState);

      dispatch({type: 'SAVE'});

      window.fetch(someUrl, {
        method: 'POST',
        body: JSON.stringify(interestingBits)
      })
      .then(checkStatus) // from https://github.com/github/fetch#handling-http-error-statuses
      .then((response) => response.json())
      .then((json) => dispatch actionCreators.saveSuccess(json.someResponseValue))
      .catch((error) =>
        console.error(error)
        dispatch actionCreators.saveError(error)
      );
    }
  },

  saveSuccess: (someResponseValue) => return {type: 'SAVE_SUCCESS', someResponseValue},

  saveError: (error) => return {type: 'SAVE_ERROR', error},

  // other real actions here
};

(N.B. $.ajax would totally work in place of the window.fetch stuff, I just prefer not to load the whole of jQuery for one function!)

The reducer just keeps track of any outstanding server request.

function reducer(state, action) {
  switch (action.type) {
    case 'SAVE':
      return Object.assign {}, state, {savePending: true, saveSucceeded: null, saveError: null}
      break;
    case 'SAVE_SUCCESS':
      return Object.assign {}, state, {savePending: false, saveSucceeded: true, saveError: false}
      break;
    case 'SAVE_ERROR': 
      return Object.assign {}, state, {savePending: false, saveSucceeded: false, saveError: true}
      break;

    // real actions handled here
  }
}

You’ll probably want to do something with the someResponseValue that came back from the server – maybe it’s an id of a newly created entity etc etc.

I hope this helps, it’s worked nicely so far for me!

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)