Home > other >  How redux thunk calls curried async thunk functions?
How redux thunk calls curried async thunk functions?

Time:10-26

My apologies if there is a question similar to this on StackOverflow, but after 3 hours of searching I couldn't find one.

I'm attempting to learn Redux and get past beginner proficiency with ReactJS and have the following thunk function:

export const listProducts = () => async (dispatch) => {
try{
    dispatch({ type:PRODUCT_LIST_REQUEST })
    const { data } = await axios.get('/api/products/') 
    dispatch({ type:PRODUCT_LIST_SUCCESS, payload: data })

}catch(error){
    dispatch({
        type:PRODUCT_LIST_FAIL,
        payload: misc_data_here
    })
}}

This function gets called in another file within a dispatch function with the relevant code as follows:

function HomeScreen() {

const dispatch = useDispatch()
const productList = useSelector(state => state.productList)
const { error, loading, products } = productList

useEffect(() => {
    dispatch(listProducts())
    
}, [dispatch])

return (rest of UI...]

My question is as follows:

How exactly does listProducts get called in this case by redux? It would need to be called like listProducts()(dispatch function here) if my (poor) understanding is correct. How exactly does the thunk (async (dispatch)) get fed the dispatch function and what actually gets returned by the listProducts function into the dispatch call within HomeScreen()?

CodePudding user response:

Redux doesn't call your listProducts action creator, you do, when you dispatch the action. The thunk redux middleware checks if the action value is an object, i.e. like a normal action object, or a function. If it is a function then the middleware invokes the curried function and passes the dispatch and getState functions so the asynchronous logic is handled and any further actions can be dispatched.

How does the middleware work?

The actual implementation of the thunk middleware is very short - only about 10 lines. Here's the source, with additional added comments:

Redux thunk middleware implementation, annotated

// standard middleware definition, with 3 nested functions:
// 1) Accepts `{dispatch, getState}`
// 2) Accepts `next`
// 3) Accepts `action`
const thunkMiddleware =
  ({ dispatch, getState }) =>
  next =>
  action => {
    // If the "action" is actually a function instead...
    if (typeof action === 'function') {
      // then call the function and pass `dispatch` and `getState` as arguments
      return action(dispatch, getState)
    }

    // Otherwise, it's a normal action - send it onwards
    return next(action)
  }

In other words:

  • If you pass a function into dispatch, the thunk middleware sees that it's a function instead of an action object, intercepts it, and calls that function with (dispatch, getState) as its arguments
  • If it's a normal action object (or anything else), it's forwarded to the next middleware in the chain

See also the Redux Async data flow for a great animated visual explanation.

  • Related