Opinionated React: Use State Colocation
Tags: react, redux, graphql, codequality
Published: 2020-04-23 18:22:56

# Intro
I’ve been working with React for over four years. During this time, I’ve formed some opinions on how I think applications should be. This is part 4 in the series of such opinionated pieces.

# Why
State location helps reduce the complexity of your application. In some cases, it can actually improve performance.

# What does colocate your state mean?
Simply put, it means to put your state as close to where it's being used. You should avoid global state unless it's absolutely necessary.

# An example
Here's some code that I've come across several times in my career. I would avoid doing this.

```tsx
import * as React from "react";

interface PersonFormState {
  firstName: string;
  lastName: string;
}

interface PersonFormAction {
  type: "SET_VALUE";
  payload: { [name: string]: string };
}

function personFormReducer(state: PersonFormState, action: PersonFormAction) {
  switch (action.type) {
    case "SET_VALUE": {
      return { ...state, ...action.payload };
    }
    default: {
      return state;
    }
  }
}

export const PersonFormContainer: React.FC = () => {
  const [state, dispatch] = React.useReducer(personFormReducer, {
    firstName: "",
    lastName: ""
  });

  const handleChange = (name: string, value: string) => {
    const updatedValue = { [name]: value };
    return dispatch({ type: "SET_VALUE", payload: updatedValue });
  };

  return <PersonForm values={state} onChange={handleChange} />;
};

interface PersonFormProps {
  values: {
    firstName: string;
    lastName: string;
  };
  onChange: (name: string, value: string) => void;
}

const PersonForm: React.FC<PersonFormProps> = ({ values, onChange }) => {
  return (
    <form>
      <label htmlFor="firstName">First name</label>
      <input
        name="firstName"
        value={values.firstName}
        onChange={event => onChange(event.target.name, event.target.value)}
      />
      <label htmlFor="lastName">Last name</label>
      <input
        name="lastName"
        value={values.lastName}
        onChange={event => onChange(event.target.name, event.target.value)}
      />
    </form>
  );
};
```

I find this code overcomplicated and hard to follow. It's also good to note that this will perform poorly, because we are causing a re-render of our entire state tree every time an input's value changes.

# Use colocation to simplify your code.
Here's how I would write this.
```tsx
import * as React from "react";

export const PersonForm: React.FC = () => {
  return (
    <form>
      <label htmlFor="firstName">First name</label>
      <PersonInput name="firstName" />
      <label htmlFor="lastName">Last name</label>
      <PersonInput name="lastName" />
    </form>
  );
};

interface PersonInputProps {
  name: string;
}

const PersonInput: React.FC<PersonInputProps> = ({ name }) => {
  const [value, setValue] = React.useState("");

  return (
    <input
      name={name}
      value={value}
      onChange={event => setValue(event.target.value)}
    />
  );
};
```

I would always start with state colocation and then lift state when needed. Keep things simple!

# Q&A
Every post I will answer a question I received on twitter. Here's this week's question.

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Best indicators for when something should be handled as application-level state vs. component-level state?</p>&mdash; jackgannon_ (@jackgannon_) <a href="https://twitter.com/jackgannon_/status/1233190382738923521?ref_src=twsrc%5Etfw">February 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

There are very few things that I consider **global**. Most state should be colocated where it's being used. Here are a couple things that I consider global:
- The current user
- Language settings
- A theme

Outside of these three, I'm not sure anything else needs to be global. 👍

# Wrapping Up
This is the 4th installment in a series of pieces I will be writing. If you enjoyed this, please comment below. What else would you like me to cover? As always, I’m open to feedback and recommendations.

Thanks for reading.

P.S. If you haven’t already, be sure to check out my previous posts in this series:

1. [An Opinionated Guide to React: Folder Structure and File Naming](https://dev.to/farazamiruddin/an-opinionated-guide-to-react-folder-structure-file-naming-1l7i)
2. [An Opinionated Guide to React: Component File Structure](https://dev.to/farazamiruddin/an-opinionated-guide-to-react-component-file-structure-1jg0)
3. [Opinionated React: State Management](https://dev.to/farazamiruddin/opinionated-react-state-management-426a)