Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Actions, Action Creators, and Thunks

Actions, Action Creators, and Thunks

Actions in Redux, how we build them, and what we use redux-thunk for.

Danielle Brook-Roberge

April 04, 2017
Tweet

More Decks by Danielle Brook-Roberge

Other Decks in Programming

Transcript

  1. Actions in Redux — In Redux, actions are the objects

    that we pass to the reducer tree to change the current state. — We treat the current state as a "sum" of the initial state and all of the actions that have happened so far. — As a plain object, each action is easily storable and viewable (in the developer tools, for example)
  2. Flux Standard Actions — On Progressive Web builds, we use

    the Flux Standard Action pattern { type: 'Type', // A string, identifying the particular action payload: { // An object of relevant values for the reducer value: 1 }, meta: {}, // Object with additional data (e.g. analytics) error: false // A flag for errors (true -> payload is an Error) }
  3. const mapDispatchToProps = (dispatch) => ({ addToCart: (productId, quantity) =>

    dispatch({ type: 'ADD_TO_CART', payload: {productId, quantity} }) })
  4. Action Creators — We can write out the action object

    explicitly wherever we want to dispatch, but this is fragile and duplicative. — Instead, we use action creator functions, one for each action type, that build the action object — This is encouraged by react-redux; the simplest form of mapDispatchToProps takes action creators
  5. const addToCart = (productId, quantity) => ({ type: 'ADD_TO_CART', payload:

    {productId, quantity} }) // ---- const mapDispatchToProps = { addToCart }
  6. redux-actions — To simplify this further, we use an action

    creator library: redux-actions — Rather than ensuring in each action creator that we follow the Flux Standard Action pattern, we instead provide functions that create the payload and meta object.
  7. import {createAction} from 'redux-actions' const addToCart = createAction( 'ADD_TO_CART', (productId,

    quantity) => ({productId, quantity}), ) // ---- const mapDispatchToProps = { addToCart }
  8. SDK Utilities — In our projects, we generally are not

    looking for complicated code to build action payloads — We have created a utility function that wraps the redux-actions createAction with a standard payload creator. — This function takes an array of parameter names, and uses them as keys in the payload object for the corresponding arguments.
  9. Thunks — We o!en need to run code as part

    of an action, rather than just build an action object for the reducers. — The redux-thunk middleware provides us a very flexible way to do this. — With it, we can pass a function to dispatch instead of an object. — That function is called a thunk.
  10. Working with Thunks — A thunk function takes the dispatch

    function as a parameter. — When dispatched, redux-thunk will call the thunk function, passing dispatch for the thunk to dispatch its own actions. — In the thunk function, we can do whatever we like, including making asynchronous HTTP requests. — The callback for the HTTP request can then dispatch actions to add data to the store.
  11. const addToStoredCart = createAction( 'ADD_TO_CART', ['productId', 'quantity'] ) const addToCart

    = (productId, quantity) => (dispatch) => { return fetch( `${ADD_TO_CART_URL}/${productId}?qty=${quantity}`, {method: 'POST'} ).then((response) => { if (response.ok) { dispatch(addToStoredCart(productId, quantity)) } }) }
  12. Additional Actions in Thunks — Thunks are not restricted to

    dispatching just one action. — We can use this, for example, to add UI feedback to an asynchronous operation — These actions can themselves be thunks; this is very important for the integration manager work.
  13. const addToCart = (productId, quantity) => (dispatch) => { dispatch(toggleCartSpinner(true))

    return fetch(/* ... */) .then(() => { dispatch(toggleCartSpinner(false)) dispatch(openModal(ADDED_TO_CART_MODAL)) // This action can be a thunk return dispatch(updateCartData()) }) }
  14. Store Access in Thunks — In addition to the dispatch

    function, thunks are passed a getState function that returns the current Redux state. — This can serve as a substitute for explicit parameter passing when the data location is unambiguous — We can use selector functions on this state to extract particular data.
  15. const addToCart = () => (dispatch, getState) => { const

    state = getState() const productId = getCurrentProductId(state) const quantity = getCurrentQuantity(stat) return fetch( `${ADD_TO_CART_URL}/${productId}?qty=${quantity}`, {method: 'POST'} ).then((response) => { if (response.ok) { dispatch(addToStoredCart(productId, quantity)) } }) }
  16. Summary — We use the redux-actions library to create action

    objects following the Flux Standard Action pattern — These are the actions that are seen by the reducer and show up in the developer tools — We also use thunk functions as actions; these are executed, dispatch their own actions, and do not show up in the dev tools.