Ben Aston Ben Aston - 4 months ago 14
Javascript Question

Positioning side-effectful behavior in Redux

I see in a project that side-effectful behavior is positioned inside actions like so:

// ...in ItemListPage.js
function onCreateItem (name, title, content) {
this.props.dispatch(createItem({ name, title, content }));
};

// ...in ItemActions.js
function createItem(post) {
return (dispatch) => {
return callApi('items', 'create', {
item: {
name: post.name,
title: post.title,
content: post.content,
},
}).then(res => dispatch(addPost(res.post)));
};
}


Is the following an accurate description of what is gong on here?

A function to be bound to an event from the Virtual DOM is created named
onCreateItem
.

When this function is run an action is dispatched to the store. The action is the result of invoking the action-creator(?)
createItem
. This action is a function-object that accepts a dispatcher.

Redux then runs the action (how does it know to do this?), passing in the dispatcher. The side-effectful logic is run (network call).

In this way the side-effectful logic is kept within the action function-object(?) and out of the reducers(?).

Is the promise returned from the action is swallowed - or can it be retrieved somehow?

What part of this code is using
redux-thunk
?

Answer Source

The best way to understand this code is to understand what redux-thunk does and how (really) simple the Middleware is.

Redux-thunk

Redux-thunk is a Middleware for redux which enhance redux with the ability to accept function actions. By default redux only accepts simple objects (that is not class objects nor functions) and then it dispatch said actions to all of the reducers in the store. What redux-thunk does is intercepting action which are functions and invokes then with a reference to the dispatch method (these actions are not dispatched to reducers), that's it it's that simple.

Your example

In your example situation is a bit more complex since we have (I assume) an async call to an external api endpoint. Let's go through it as the execution flows from the user interaction with the control to the item.

  1. User interaction - some user interaction raises the onCreateActoin event handler, in turn this
  2. Invokes the action creator creator createAction.
  3. The created action (a function with the signature: (reducer) => promise is passed to store.dispatch.
  4. The action is passed down the Middleware chain.
  5. Redux-thunk catches the action and calls the function with one parameter - reducer.
  6. The function creates a new Promise via callApi.
  7. You add a listener to the promise on success (.then).
  8. The promise is returned.
  9. Redux-thunk breaks the Middleware chain, terminating any additional processing of the action.
  10. The returned promise bubbles up and is returned by the original dispatch call (in onCreateAction)
  11. (async) callApi's promise finishes.
  12. (async) the then we added is called.
  13. (async) addPost is called and the result is passed to store.dispatch.