How to fire AJAX calls in response to the state changes with Redux? How to fire AJAX calls in response to the state changes with Redux? ajax ajax

How to fire AJAX calls in response to the state changes with Redux?


Using store.subscribe()

The easiest way is to simply use store.subscribe() method:

let prevStatestore.subscribe(() => {  let state = store.getState()  if (state.something !== prevState.something) {    store.dispatch(something())  }  prevState = state})

You can write a custom abstraction that lets you register conditions for side effects so they are expressed more declaratively.

Using Redux Loop

You might want to look at Redux Loop which let you describe effects (such as AJAX) calls together with state updates in your reducers.

This way you can “return” those effects in response to certain actions just like you currently return the next state:

export default function reducer(state, action) {  switch (action.type) {    case 'LOADING_START':      return loop(        { ...state, loading: true },        Effects.promise(fetchDetails, action.payload.id)      );    case 'LOADING_SUCCESS':      return {        ...state,        loading: false,        details: action.payload      };

This approach is inspired by the Elm Architecture.

Using Redux Saga

You can also use Redux Saga that lets you write long-running processes (“sagas”) that can take actions, perform some asynchronous work, and put result actions to the store. Sagas watch specific actions rather than state updates which is not what you asked for, but I figured I’d still mention them just in case. They work great for complicated async control flow and concurrency.

function* fetchUser(action) {   try {      const user = yield call(Api.fetchUser, action.payload.userId);      yield put({type: "USER_FETCH_SUCCEEDED", user: user});   } catch (e) {      yield put({type: "USER_FETCH_FAILED",message: e.message});   }}function* mySaga() {  yield* takeEvery("USER_FETCH_REQUESTED", fetchUser);}

 No One True Way

All these options have different tradeoffs. Sometimes people use one or two, or even all three of them, depending on what turns out to be most convenient for testing and describing the necessary logic. I encourage you to try all three and pick what works best for your use case.


You can use a middleware to fire up your remote actions in response to the local action.

Let say I have a local action:

const updateField = (val) => {  {type: UPDATE_FIELD, val}}

And a input field with:

<input type='text' onChange={this.props.updateField.bind(this.val)}>

So in a nutshell when you type inside of the field it fires your action that in turn changes the state via reducer. Lets just forget how this action was passed to the component or what this.val is - we just assume this has been already solved and it is working.

All is fine about this setup but it only changes your state locally. To update the server you will have to fire another action. Lets build it:

const updateFieldOnServer = (val) => {  return (dispatch) => {    MAKE_AJAX.done(      FIRE_SOME_ACTIONS_ON_SUCCESS    ).failure(      FIRE_SOME_ACTIONS_ON_FAILURE    )  }} 

This is just an simple thunk async action thats somehow makes ajax request, returns promises and does something else on success or failure.

So the problem we have now is that I want both of this actions to be fired when I change the state of my input but I can't have the onChange to take two functions. So I will create a middleware named ServerUpdatesMiddleware

import _ from 'lodash'import {  UPDATE_FIELD,} from 'actionsPath'export default ({ dispatch }) => next => action => {  if(_.includes([UPDATE_FIELD], action.type)){    switch(action.type){      case UPDATE_FIELD:        dispatch(updateFieldOnServer(action.val))    }  }  return next(action)}

I can add it to my stack:

import ServerUpdatesMiddleware from 'pathToMe'const createStoreWithMiddleware = applyMiddleware(  ServerUpdatesMiddleware,  thunkMiddleware,  logger)(createStore);

And right now every single time when updateField action will be dispatched It will automatically dispatch updateFieldOnServer action.

This is just example I think will describe the problem easily - this problem can be fixed in many other different ways but I think it nicely fits the requirements. It is just how I do things - hope it will help you.

I am using middlewares all the time and have many of them - never had any problem with this approach and it simplifies the application logic - you only have to look in a single place to find out whats going on.


Having modules that subscribe to the state updates and the launch Ajax requests (firing actions as they go) seems fine to me, since it puts the stores/reducers firmly in charge of triggering requests. In my large app, ALL Ajax requests and other async behaviours are done this way, so all actions can be just payloads, with no concept of 'action creators'.

If possible, avoid cascading sync actions. My async handlers never fire actions synchronously, but only once the request completes.

In my view, this is a much more functional approach than async action creators, which you may or may not prefer!