3

I am building a Redux application (my first) and am a little unclear about how much coupling is appropriate between actions.

My application has several forms whose values are serialized in the url.

For example, there is an input field for a particular search, and upon key-up a url parameter is updated. There are several other input fields that follow this pattern.

In my top-level index.js I have several blocks of code that look like this:

// Within the declaration of a high-level component
onForm1Change={(key, value) => {
        // Listened to by "formValues" state cross-section reducer
        store.dispatch({
            type: actions.FORM1_CHANGE,
            key: key,
            value: value
        });

        // Listened to by "url" state cross-section reducer, leads to a url param update.
        // Has it's own logic that is based upon the formValues state.
        // Must run after FORM1_CHANGE finishes
        store.dispatch({
            type: actions.UPDATE_URL,
            formValues: store.getState().formValues
        });
    }
}

Something about actions like UPDATE_URL doesn't feel right. This action doesn't stand on its own...it relies on other actions to be dispatched first.

Is this sort of coupling between actions a code smell? Are there any common techniques to de-couple/refactor these actions?

Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
  • The main purpose of dispatch is to change the state in the store. The UPDATE_URL action does not make sense since it is sending data that comes from within the store itself, so nothing change. – DJ. May 30 '17 at 01:27
  • @DJ. I probably wasn't quite clear about this, but the reducer that listens to UPDATE_URL isn't simply passing data through...it has it's own logic that needs to run which uses the passed-in formValues as an input (I added a code comment to reflect this) – Jonathan.Brink May 30 '17 at 01:29

2 Answers2

3

I think that's totally OK way of chaining synchronous actions. You can also use middleware like redux-thunk for this purpose to make it simpler to read (as you will store your actions dispatcher function as an action creater). Here is some article on this topic.

GProst
  • 9,229
  • 3
  • 25
  • 47
1

This is how i did it,

Defined a redux store middleware that will detect if any dispatched action has a queryString property, and update url with it.

import createHistory from "history/createBrowserHistory";

function queryStringMiddleware(history) {
  return store => next => action => {
    const { payload } = action;
    if (payload.queryString) {
      history.push({
        search: queryString
      });
    }
    next(action);
  };
}

const history = createHistory();
const middlewares = [queryStringMiddleware(history)];
const store = configureStore({}, middlewares);

Then in your action:

const onForm1Change = (key, value) => {
  store.dispatch({
    type: actions.FORM1_CHANGE,
    key: key,
    value: value,
    queryString: "?the=query"
  });
};
Faris
  • 544
  • 2
  • 8