Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

8/14/2020 What the heck is a 'thunk'?

Black Lives Matter. Donate.

Dave Ceddia Courses All Posts About

What the heck is a 'thunk'?


Q: What is a ‘thunk’?

A: The sound your head makes when you first hear about redux-thunk .

Ok sorry, that was awful.

But seriously: Redux Thunk is a really confusing thing when you first hear about it.
I think it’s mostly because of that word “thunk.” So let’s clear that up first.

thunk, n.
A thunk is another word for a function. But it’s not just any old function. It’s a
special (and uncommon) name for a function that’s returned by another. Like this:

jsx

function wrapper_function() {
// this one is a "thunk" because it defers work for later:
return function thunk() { // it can be named, or anonymous
console.log('do stuff now');
};
}

You already know this pattern. You just don’t call it “thunk.” If you want to execute
the “do stuff now” part, you have to call it like wrapper_function()() – calling
it twice, basically.
https://daveceddia.com/what-is-a-thunk/ 1/13
8/14/2020 What the heck is a 'thunk'?

redux-thunk
So how does this apply to Redux?

Well, if you’re familiar with Redux, you’ll know that it’s got a few main concepts:
there are “actions”, “action creators”, “reducers”, and “middleware.”

New to Redux? If actions and reducers and middleware have your head in a
spin, don't rush in to thunks!

Learn the basics with this free 3-day email course.

You'll understand what Redux is for, how to use it with React, and how to
deal with immutability.

Your email address

Get the First Lesson


3-day course and an article each week.
Unsubscribe any time.

Actions are just objects. As far as Redux is concerned, out of the box actions must
be plain objects, and they must have a type property. Aside from that, they can
contain whatever you want – anything you need to describe the action you want to
perform.

Actions look like this:

jsx

// 1. plain object
// 2. has a type
// 3. whatever else you want
{
type: "USER_LOGGED_IN",

https://daveceddia.com/what-is-a-thunk/ 2/13
8/14/2020 What the heck is a 'thunk'?

username: "dave"
}

And, since it’s kind of annoying to write those objects by hand all the time (not to
mention error-prone), Redux has the concept of “action creators” to stamp these
things out:

jsx

function userLoggedIn() {
return {
type: 'USER_LOGGED_IN',
username: 'dave'
};
}

It’s the same exact action, but now you can “create” it by calling the
userLoggedIn function. This just adds one layer of abstraction.

Instead of writing the action object yourself, you call the function, which returns
the object. If you need to dispatch the same action in multiple places around your
app, writing action creators will make your job easier.

Actions are Boring


Isn’t it kind of funny that Redux’s so-called “actions” don’t actually do anything?
They’re just objects. Plain and simple and inert.

Wouldn’t it be cool if you could actually make them do something? Like, say, make
an API call, or trigger other actions?

Since reducers are supposed to be “pure” (as in, they don’t change anything outside
their scope) we can’t do any API calls or dispatch actions from inside a reducer.

https://daveceddia.com/what-is-a-thunk/ 3/13
8/14/2020 What the heck is a 'thunk'?

If you want an action to do something, that code needs to live inside a function.
That function (the “thunk”) is a bundle of work to be done.

It would be nice if an action creator could return that function – the bundle of work
– instead of an action object. Something like this:

jsx

function getUser() {
return function() {
return axios.get('/current_user');
};
}

If only there were some way to teach Redux how to deal with functions as actions…

Well, this is exactly what redux-thunk does: it is a middleware that looks at every
action that passes through the system, and if it’s a function, it calls that function.
That’s all it does.

The only thing I left out of that little code snippet is that Redux will pass two
arguments to thunk functions: dispatch , so that they can dispatch new actions
if they need to; and getState , so they can access the current state. So you can do
things like this:

jsx

function logOutUser() {
return function(dispatch, getState) {
return axios.post('/logout').then(function() {
// pretend we declared an action creator
// called 'userLoggedOut', and now we can dispatch it
dispatch(userLoggedOut());
});
};
}

https://daveceddia.com/what-is-a-thunk/ 4/13
8/14/2020 What the heck is a 'thunk'?

Update: As rixman mentions in the comments, the getState function can be


useful for deciding whether to fetch new data, or return a cached result, depending
on the current state.

That’s about it. That’s what redux-thunk is for.

A Very Small Library Indeed


The entirety of the redux-thunk library is this code right here:

jsx

function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
// This gets called for every action you dispatch.
// If it's a function, call it.
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}

// Otherwise, just continue processing this action as u


return next(action);
};
}

const thunk = createThunkMiddleware();


thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

After you install redux-thunk in your project, and apply the middleware, every
action you dispatch will pass through this bit of code. It calls actions that are
functions (and returns whatever they return), and otherwise passes the action
along to then next middleware, or to Redux itself (which is what next(action)
does).

https://daveceddia.com/what-is-a-thunk/ 5/13
8/14/2020 What the heck is a 'thunk'?

Set up redux-thunk in your project


If you have a project that already has Redux set up, adding redux-thunk is two
steps.

First, install the package:

bash

npm install --save redux-thunk

Then, wherever you have your Redux setup code, you need to import redux-
thunk and insert its middleware into Redux:

jsx

// You probably already import createStore from 'redux'


// You'll need to also import applyMiddleware
import { createStore, applyMiddleware } from 'redux';

// Import the `thunk` middleware


import thunk from 'redux-thunk';

// Import your existing root reducer here.


// Change this path to fit your setup!
import rootReducer from './reducers/index';

// The last argument to createStore is the "store enhancer".


// Here we use applyMiddleware to create that based on
// the thunk middleware.
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);

Just make sure you wrap thunk in the applyMiddleware call, or it won’t work.

https://daveceddia.com/what-is-a-thunk/ 6/13
8/14/2020 What the heck is a 'thunk'?

After this, you’re all set: you can now dispatch functions that do whatever you
need.

And now that you have redux-thunk set up, you can learn how to fetch data with
Redux.

Learn the basics of React in 5 days


Finally understand how React works! You will:

🎉 Get something on screen


💄 Write dynamic components
🏃 Make it interactive
😎 Fetch real data
Put it online

5 days, 5 emails. Walk away with the basics and a plan!

Get Lesson 1 right now 👇


Your email address

Send Me Lesson 1
I respect your email privacy. Unsubscribe any time.

Learning React can be a struggle — so many libraries and tools!


My advice? Ignore all of them :)
For a step-by-step approach, check out my Pure React workshop.

https://daveceddia.com/what-is-a-thunk/ 7/13
8/14/2020 What the heck is a 'thunk'?

Learn to think in React


90+ screencast lessons
Full transcripts and closed captions

All the code from the lessons


Developer interviews

Start learning Pure React now ➞

“ Dave Ceddia’s Pure React is a work of enormous clarity and depth. Hats off. I'm
a React trainer in London and would thoroughly recommend this to all front
end devs wanting to upskill or consolidate.

Alan Lavender
@lavenderlens

Login

Add a comment

M ↓   MARKDOWN ADD COMMENT

wekempf
W
https://daveceddia.com/what-is-a-thunk/ 8/13
8/14/2020
W What the heck is a 'thunk'?
0 points  ·  45 months ago

Your definition of a thunk doesn't match the generally held definition of a thunk. A thunk is a small
function that generally adapts another, for example adapting the calling convention.
http://stackoverflow.com/qu...

Dave Ceddia
D 0 points  ·  45 months ago

One of those answers (not the accepted one, but the one with the most upvotes) says a thunk may be
"a piece of code to perform a delayed computation (similar to a closure)". That's pretty much the way
I'm using it here.

wekempf
W 0 points  ·  45 months ago

Yes, but note that that answer includes two other definitions and links to the Wikipedia article who's
opening paragraph gives a clear definition that doesn't include any part of this definition? Not saying
that the definition you provided is entirely wrong (though I would say it's not precise enough even
for this one application of the term), just that it's far too narrow and imprecise. Anyone not knowing
what a thunk is would read this definition and be le with the mistaken idea that they understand
what a thunk is, only to be very badly confused when confronted with the usage of the term nearly
everywhere else that it's used. Even just adding a sentence to explain this definition is for how the
term thunk is used by redux would be better.

rixman
R 0 points  ·  45 months ago

also worth mentioning is that the second argument is a callable function: function (dispatch, getState) { ... }
that returns the state. Great for deciding whether to return a cached result or fetching new data for
example

Marc Bernstein
M 0 points  ·  45 months ago

also getState comes in handy when using combineReducers to pass the di erent pieces of state to
specific reducers.

Dave Ceddia
D 0 points  ·  45 months ago

Good tip, thanks! I added it in.

Prathap
P 0 points  ·  45 months ago

looks like close to closure to me :)

https://daveceddia.com/what-is-a-thunk/ 9/13
8/14/2020 What the heck is a 'thunk'?

Tre
T 0 points  ·  28 months ago

HOF's indeed use closures. A closure does not "have" to be a HOF.

Aquiles Castro
A 0 points  ·  45 months ago

"It’s a special name for a function that’s returned by another"


Why isn't this just a higher order function???

tyler
T 0 points  ·  45 months ago

Are you asking why they aren't called Higher order functions?
HOF's are functions that take functions as arguments (callbacks). Thunks are functions returned
somewhere in the body of another function.

Tre
T 0 points  ·  28 months ago

A hof can actually just return a fn, does not "have" to take a fn too, but can.
At least, thats been my experience since I started writing FP in JS, since Dec 2012.

Dave Ceddia
D 0 points  ·  28 months ago

Yep, this. I think I should make a Venn diagram of these terms haha. HOF / HOC / thunk / closure...

Tre
T 0 points  ·  28 months ago

Agreed, but ooof, venn diagrams though :)

Kj Huang
K 0 points  ·  33 months ago

why your thunk function return axio.pos..., I mean, does it matter if thunk function itself return sth?

Dave Ceddia
D 0 points  ·  33 months ago

Ah good question - the thunk function doesn't HAVE to return something, but if it does, that return
value will be the value returned by the original dispatch call, which allows you to chain dispatch calls
like this:
dispatch(logOutUser()).then(() => { // do something a er logout })

https://daveceddia.com/what-is-a-thunk/ 10/13
8/14/2020 What the heck is a 'thunk'?

Kj Huang
K 0 points  ·  33 months ago

thank you, I also find a good explanation on https://www.npmjs.com/packa...

finferflu
F 0 points  ·  30 months ago

Thanks a lot for the very clear explanation, very helpful!

Sherlock Vilmes Vic Vilmes


S 0 points  ·  27 months ago

1. The thunk function , in this case, logOutUser, does not HAVE to return anything. Then is it correct to
say, "without using thunk, action creator functions are meant to return action objects"?

2. a er npm installed thunk, how did we configure it so that it knows to look through reducers and do its
work ?
Thanks, Dave

Dave Ceddia
D 0 points  ·  27 months ago

1. Yes that's right, action creators normally return action objects -- that is, an object with a "type"
property. Adding the thunk middleware gives Redux the ability to handle actions that are
functions instead of action objects.

2. I added a section to the end of the post explaining how to configure it.

Jason Kao
J 0 points  ·  27 months ago

Finally, an article that actually helps me understand what redux-thunk is. Just got my first real so dev job
and I'm already struggling with explaining React and Redux to my non-technical boss and clients in
writing. I hope I can one day write as clearly and concisely as you

Eugene Vedensky
E 0 points  ·  25 months ago

Still trying to really confidently grasp this concept: is it accurate to say the value of thunk is that can you
dispatch a function as an action?... and ultimately dispatch a traditional action object a er some work
(perhaps async) has been performed?
If this is the case, can't we perform the work in the component event handlr then dispatch when the
supposed promise resolves ? for example,
const onClick = ( e ) => { fetch('someurl').then( result => result .json( )).then( data => this.props.dispatch(
actionCreator(data) ) };

https://daveceddia.com/what-is-a-thunk/ 11/13
8/14/2020 What the heck is a 'thunk'?

If my rational is correct, it seems that the real value of thunk is to keep our components clean from this
kind of cluttered code and properly decouple our views from the call logic.
If someone would be so kind as to a irm my thought or provide some feedback, thanks!

Dave Ceddia
D 0 points  ·  24 months ago

Yep that's accurate. Dan Abramov's Redux course on Egghead.io actually does it in the way you
describe, having the component do the dispatching and the asynchronous work. It's a tradeo
between keeping the code in one place vs. decoupling the components from the API call logic.
There's also a middle ground where you can put the fetch() call and any necessary transformations into
an api.js file, and then elsewhere in the app you can import those functions and call e.g. "getUsers()" or
whatever. Keeps API details out of the rest of your code.

JBallin
J 0 points  ·  24 months ago

typo (missing k at end):


$ npm install --save redux-thun

Archpriest
A 0 points  ·  18 months ago

thunks a lot

Dennis Loska
D 0 points  ·  17 months ago

Thank you now I know what I am doing :D

Deden Habibi
D 0 points  ·  14 months ago

It is the clearly most human explanation of thunk. Thank you :D

Julian Jacobs
J 0 points  ·  13 months ago

finally a simple article on this topic. Thanks!

Anton Bagdatyev
A 0 points  ·  11 months ago

Thank you for this article.


I am quite new to Redux and have a little doubt. What happens if you happen to register the thunk
middleware before another middleware?

https://daveceddia.com/what-is-a-thunk/ 12/13
8/14/2020 What the heck is a 'thunk'?

E.g.:
const store = createStore( rootReducer, applyMiddleware(thunk, createLogger(...)) );

If an action creator returns a function, the thunk middleware executes it and returns its return value to
Redux. At this point, will the next middleware (and, if so, all the eventual middlewares registered a er it)
be ignored? In my example, if my thunk returns a function which performs an AJAX call, will the logger
middleware be ignored?

Eldor Juraev
E 0 points  ·  10 months ago

The only tutorial that could indeed explain me what thunk is for! Thank you Dave, for a great job!

Dave Ceddia
D 0 points  ·  10 months ago

You're welcome! Glad it helped!

Rubanraj
0 points  ·  9 days ago

Awesome explanation.

Dave Ceddia MODERATOR


D 0 points  ·  9 days ago

Thanks! :)

Powered by Commento

© 2020 Dave Ceddia.

https://daveceddia.com/what-is-a-thunk/ 13/13

You might also like