Redux Thunk

What the thunk?

In computer programming, a thunk is a subroutine used to inject an additional calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. They have a variety of other applications in compiler code generation and modular programming.

 

The term originated as a jocular derivative of "think".

Thunky Redux

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

redux-thunk is a plug-in to extend redux (via middleware).

TL;DR it lets you do async stuff

Thunktastic Diagram

Installing redux-thunk

1. npm i redux-thunk

2. Wherever you are calling createStore:

import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

/**
 * Build a Redux Store and apply middleware
 */
function configureStore() {
  const store = createStore(
    rootReducer,
    // enable the dev tools extension if you have it installed
    compose(
      applyMiddleware(thunk),
      window.devToolsExtension ? window.devToolsExtension() : f => f
    )
  );
  return store;
}

export default configureStore;

What does a thunk look like?

An action creator...that returns a function...that can dispatch other actions.

function incrementIfOdd() {
  // the function has two params:
     // dispatch calls the reducer with an action
     // getState fetches the current Redux state from the store
  return (dispatch, getState) => {
    const { counter } = getState();

    if (counter % 2 === 0) {
      return;
    }

    dispatch(increment());
  };
}

What does a real thunk look like?

export function fetchTodosRequest() {
  // THUNK!
  return async (dispatch, getState) => {
    // dispatch an action describing that we are making a request
    dispatch({ type: FETCH_TODOS_REQUEST });

    try {
      // call the API (async operation)
      const todos = await fetchTodos();

      // dispatch a success action if it works
      dispatch(fetchTodosSuccess(todos));

    } catch (err) {
      // dispatch a fail action if API call fails
      dispatch(fetchTodosFail(err));

      // manually reject the promise
      return Promise.reject();
    }
  };
}

What if I need to wait for a thunk to finish?

async componentDidMount() {

  // before component renders, fetch todos first
  try {
    await this.props.fetchTodos();
  } catch(e) {
    return;
  }

  // if we get here successfully, we're done loading!
  this.setState({
    loading: false
  });
}

The following code works as long as your thunk returns a Promise (async functions do this automatically)

Check out the "thunk" branch on my React Redux Data Flow app here

Additional Resources

Made with Slides.com