A Better useReducer: Colocating Side Effects With Actions Using useReducer
Tags: react, usereducer, sideeffects, reason
Published: 2019-06-24 04:32:13

---
title: A Better useReducer: Colocating Side Effects With Actions Using useReducer
published: true
description: while we want to keep our reducers pure, the action sent via dispatch often has an implicit intent to trigger a side effect, what if we can maintain purity of the reducer while allowing code that belongs together to remain together
tags: React, useReducer, Side Effects, Reason
cover_image: https://files.conorhastings.now.sh/ccc.png
---

The word colocation gets thrown around a lot these days.

*Styles* in my mind being the biggest example There seems to be a near constant conversation revolving around *colocating* styles with components, the argument often being that styles are **part** of the component and without them it would not be what it is. Putting the two together allows one to reason in a single place about what will appear on the page. 

I won't get into that here because I wish to spend most of my time *not* arguing about styles on twitter. 

What I'll talk about instead is React hooks, I believe they have introduced a place where we have an astonishing chance for colocation in data fetching and data flow in general. 

I didn't randomly choose to put bread and cheese emojis in the header image because those just so happened to be the two things currently on my mind, I see them as a great example of things that are commonly *colocated* in this real world everyone keeps telling me about (but I don't get MTV I respond to rapturous laughter). 

As hooks gain more and more popularity, specifically **useReducer** we often begin to see it paired with **useEffect** in many different sorts of ad hoc ways in fetching data. Something like this contrived example below:

```jsx
function Avatar({ userName }) {
  const [state, dispatch] = useReducer(
    (state, action) => {
      switch (action.type) {
        case FETCH_AVATAR: {
          return { ...state, fetchingAvatar: true };
        }
        case FETCH_AVATAR_SUCCESS: {
          return { ...state, fetchingAvatar: false, avatar: action.avatar };
        }
        case FETCH_AVATAR_FAILURE: {
          return { ...state, fetchingAvatar: false };
        }
      }
    },
    { avatar: null }
  );

  useEffect(() => {
    dispatch({ type: FETCH_AVATAR });
    fetch(`/avatar/${usereName}`).then(
      avatar => dispatch({ type: FETCH_AVATAR_SUCCESS, avatar }),
      dispatch({ type: FETCH_AVATAR_FAILURE })
    );
  }, [userName]);

  return <img src={!fetchingAvatar && state.avatar ? state.avatar : DEFAULT_AVATAR} />
}
```

This code, barring mistakes I almost definitely made, should work, but the thought of slogging through this every time I'm doing something like loading an avatar is a nightmare. But I still love the **useReducer** pattern so whatttttt am I to do.

I believe **ReasonReact** has already solved for this with the [**reducerComponent**](https://github.com/reasonml/reason-react/blob/master/docs/state-actions-reducer.md)

**ReasonReact** provides the functions *Update*, *UpdateWithSideEffect*, *SideEffect*, and *NoUpdate* which are than used to wrap the value returned from the reducer allowing not so much the colocating of side effects with the reducer (which we still want to keep pure) but the colocation of the **INTENT** of side effects that will follow. 

We can take this idea and bring it over to the world of React hooks to give us a somewhat similar experience, remove excessive code like that seen above, and provide a common pattern for teams to execute actions that lead to side effects. Hopefully causing easier understanding of the code, easier to review pull requests, and the actual important reason, less bugs reaching the end user.

Here's what the above code might look like in that world. 

```jsx
function Avatar({ userName }) {
  const [{ avatar }, dispatch] = useReducerWithSideEffects(
    (state, action) => {
      switch (action.type) {
        case FETCH_AVATAR: {
          return UpdateWithSideEffect({ ...state, fetchingAvatar: true }, (state, dispatch) => {
                fetch(`/avatar/${usereName}`).then(
                  avatar =>
                    dispatch({
                      type: FETCH_AVATAR_SUCCESS,
                      avatar
                    }),
                  dispatch({ type: FETCH_AVATAR_FAILURE })
                );
          });
        }
        case FETCH_AVATAR_SUCCESS: {
          return Update({ ...state, fetchingAvatar: false, avatar: action.avatar });
        }
        case FETCH_AVATAR_FAILURE: {
          return Update({ ...state, fetchingAvatar: false })
        }
      }
    },
    { avatar: null }
  );

  useEffect(() => dispatch({ type: FETCH_AVATAR }) , [userName]);

  return <img src={!fetchingAvatar && state.avatar ? state.avatar : DEFAULT_AVATAR} />;
}
```

We're now able to colocate the fetching of the avatar with our declaration of intent to fetch the avatar, allowing us to follow in one section of code exactly what is happening.

I believe **ReasonReact** got this **super duper extremely correct** and am excited to use this pattern with React hooks as I develop new features.

You can see a library implementing this pattern [here](https://github.com/conorhastings/use-reducer-with-side-effects) and to be honest it's not all that difficult to do this or something similar on your own.

If you're interested in hearing more on the topic and are the SF Bay Area I'll be speaking on the topic at the [July React Meetup](https://www.meetup.com/ReactJS-San-Francisco/events/255322421/)

Looking forward to hearing what everyone thinks!