Thunk

Damely Tineo
3 min readDec 31, 2020

Thunk. What a strange word.

“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.” — Wikipedia

In simpler terms, thunk refers to a sequence of instructions embedded within another sequence of instructions by way of a function return from inside another function! Now, why on earth would we do that?! Well, as explained above, sometimes we need to delay or alter the course of our program or calculations. The more complex our applications, the longer our runtime, or the more involved our functions will be, therefore, the more likely we’ll want to do things like this.

As an example, here’s how I implement Thunk in my React Redux Storyteller project. Using redux-thunk*, I added a loading property to my stories to load and display a loading message while stories are being fetched.

*A Redux middleware that allows users to return a function within an action creator function to make asynchronous web requests for data in Redux.

When the StoriesContainer mounts (when a user first visits Storyteller or after a story is successfully added):

  1. The fetchStories() action creator function is invoked.
  2. Directly after invoking, fetchStories() returns a function (return()) with an argument of the store’s dispatch function — this allows us to return multiple actions, instead of returning a plain JavaScript object.
  3. The first action dispatched indicates a loading state (we are making the request to the API).
  4. Next, the fetch() method is called, returning a Promise.
  5. Finally, when this Promise resolves, our final action is THEN dispatched. We send our fetched data to its corresponding stories reducer. If loading is true, we can display a loading message in JSX.
class StoriesContainer extends Component {componentDidMount() {
this.props.fetchStories();
this.props.fetchTopStory();
}
...
}

fetchStories() action creator function:

export const fetchStories = () => {
return (dispatch) => {
dispatch({ type: 'LOADING_STORIES' });
fetch('http://localhost:3000/stories')
.then(response => response.json())
.then(stories => dispatch({ type: 'FETCH_STORIES', payload: stories }));
};
}

Reducer:

export const storiesReducer = (state = { stories: [], loading: false }, action) => {
switch (action.type) {
case 'FETCH_STORIES':
return {
stories: action.payload,
loading: false
}

case 'LOADING_STORIES':
return {
...state,
stories: [...state.stories],
loading: true
}

...

default:
return state;
}
}

To display loading message:

class StoriesContainer extends Component {componentDidMount() {
this.props.fetchStories();
this.props.fetchTopStory();
}

render() {
if(this.props.loading) {
return <div>LOADING...</div>;
}
return (
...
);
}

const mapStateToProps = state => {
return {
topStory: state.stories.story,
stories: state.stories,
user: state.auth.currentUser,
loading: state.stories.loading
}
}

Since fetch requests in JavaScript are asynchronous, without thunk, dispatch({ type: ‘FETCH_STORIES’, payload: stories }) would start running before the web request (our Promise) resolves and we have a response that we can actually work with (parse into JSON). Yikes!

Furthermore, as we all well know, retrieving data can sometimes take a while and NO ONE likes staring at an empty screen not knowing what is going on while waiting. Thunk allows us to make use of this in-between or loading state until our data is retrieved, our store state is updated (via the reducer), and finally, our component displays the desired state information.

Convinced? Cool! Here’s how to install and use the NPM Redux Thunk package:

  • In your IDE run the following command: npm install — save redux-thunk
  • Next in index.js, import applyMiddleware() from redux, along with thunk from the redux-thunk package and pass in applyMiddleware(thunk) as an argument to createStore.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
...

const store = createStore(rootReducer, applyMiddleware(thunk));

...

And you're all set!

Thunk you for reading!

--

--