in the Boilerplate I am using for a React Redux project I came across this comment in the code:
This is a thunk, meaning it is a function that immediately returns a function for lazy evaluation. It is incredibly useful for creating async actions, especially when combined with redux-thunk!
Now, if I understand this correctly, lazy evaluation is the process of returning a function. What is the purpose of returning a function though, and how is this great for creating async actions?
Oh also, is a thunk just a function?
A thunk is a function that takes no arguments and returns something (or does something as a side effect). Lazy evaluation is the process of deferring the evaluation of an expression until later, and this can be done with thunks:
// Not lazy
var value = 1 + 1 // immediately evaluates to 2
// Lazy
var lazyValue = () => 1 + 1 // Evaluates to 2 when lazyValue is *invoked*
You can also make return values lazy:
// Not lazy
var add = (x, y) => x + y
var result = add(1, 2) // Immediately evaluates to 3
// Lazy
var addLazy = (x, y) => () => x + y;
var result = addLazy(1, 2) // Returns a thunk which *when evaluated* results in 3.
Finally we can defer some asynchronous action:
// Not lazy
var callApi = spec => fetch(spec.url, spec.options);
// Immediately returns a Promise which will be fulfilled when the network response is processed.
var result = callApi({url: '/api', options: {}});
// Lazy
var callApiLazy = spec => () => fetch(spec.url, spec.options);
var result = callApiLazy({url: '/api', options: {}});
// result is a thunk that when evaluated will return a Promise ...
// which will be fulfilled when the network response is processed.
Now a thunk does not have to take zero arguments - you could return a lazy value that requires more arguments to successfully evaluate. This is properly known as "currying":
// Curried add (not lazy)
var add = x => y => x + y
var add3 = add(3)
var result = add3(7) // Immediately evaluates to 10
redux-thunk lets you return functions, rather than objects, as actions and invokes your function with a dispatch
function. You can then lazily produce an action (or actions) either synchronously or asynchronously. Most of the time, you would want to use this to allow you to dispatch asynchronously.
See also: