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

Actions, Action Creators, and Thunks

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Actions, Action Creators, and Thunks

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

Avatar for Danielle Brook-Roberge

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.