What the heck is a 'thunk'?

Dave Ceddia bio photo By Dave Ceddia Comment

Thunk! (the redux kind)

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:

function not_a_thunk() {
	// this one is a "thunk" because it defers work for later:
	return function() {
		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 not_a_thunk()() – calling it twice, basically.

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.”

At its heart, though, Redux is really simple. Actions are just objects – and they are expected to only be objects. They look like this:

{
	type: "USER_LOGGED_IN",
	username: "dave"
}

And, since it’s kind of annoying to build objects by hand all the time, Redux has “action creators” that build these things:

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

Same action, but now you can “create” it by calling the userLoggedIn function.

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

Wouldn’t it be cool if you could actually make them do something? Like, say, make an AJAX call, or trigger other actions? Because reducers are supposed to be “pure” (as in, they don’t change anything) we couldn’t put that work inside a reducer.

If you wanted an action to do something, that code would need to live inside a function…

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

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:

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());
		});
	}
}

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.

You might like my book because it teaches React in a way that’ll fill in the missing gaps.

comments powered by Disqus