A Mental Model for Writing React Hook Components
Tags: react, hooks, javascript, typescript
Published: 2020-09-17 17:17:22

By now we've probably all written a component that uses React hooks. Many times, however, we struggle with what hooks we need or if we need a custom hook.

This article will explain my mental model or how I go about determining how to write my component. We'll do this a step at a time so you can see my process and I'll tell you what I'm thinking at each step.

## Write the render first

I think visually, so I like to start with what I'd like to render. This will help me determine what data elements I'm going to need.

For example, if I'm writing a weather component that displays the temp and current conditions, I start with the markup.

> 💭 What I'm thinking...
> I want to display the current temperature and weather conditions for a given city.

It could be something like this.

```js
const Weather = ({ city }) => {
  return <span>{temp}˚F - {conditions}</span>;
};
```

Cool! Now I know what I want to render and in doing so, I've discovered what pieces of data that I'll need.

## Stub in the data

> 💭 What I'm thinking...
> I'd like to see my markup visually before I proceed.

At this point, the app won't compile as there are missing variables, so often I'll mock that data so I can see things working.

```js
const Weather = ({ city }) => {
  const temp = 72;
  const conditions = 'Perfect';

  return <span>{temp}˚F - {conditions}</span>;
};
```

As you can see above, I've mocked `temp` and `conditions`. Now when I run the app I can see my component.

> Note: In reality, your component will probably need to have a loading state (unless you're using Suspense), as the data is loaded asynchronously, but for simplicity's sake, I'm not showing that here.

If I like what I see visually, I can move on to actually getting the data. And for this, I like to encapsulate everything into a custom hook.

## Write the call to the custom hook

> 💭 What I'm thinking...
> What will the custom hook signature look like?

We now have everything we need to write a custom hook. We know the input (i.e. `city`) and the output (i.e. `temp` and `conditions`). **This is our contract.**

Now let's replace the mock data in the component with a call to our yet-to-be-written custom hook. Our component will now look like this.

```js
const Weather = ({ city }) => {
  const { temp, conditions } = useWeather(city);

  return <span>{temp}˚F - {conditions}</span>;
};
```

## Write a custom hook

> 💭 What I'm thinking...
> Now I'll write a custom hook that satisfies the contract.

With everything in place, it's time to write a hook that fulfills our contract.

Here is a stubbed out custom hook called `useWeather` which, for now, will return mocked data.

```js
const useWeather = (city) => {
  return {
    temp: 72,
    conditions: 'Perfect',
  };
};
```

The app should still run as the mock data is coming from the custom hook.

It should be noted that how we get the data in the hook is an "implementation detail". Meaning that the component shouldn't care how or where it gets the data. We could write something that fetches from a REST endpoint or uses Apollo to get the data from a GraphQL server. The point is that once we've designed the contract, it doesn't matter to the component.

## Let's recap

When designing a component...

1. Start with the rendered markup
1. Stub in the variables needed
1. Replace the stubbed variables with a call to get the data
1. Write a custom hook that fulfills the contract

I find that if I follow these steps, using this as my mental model, writing React components with hooks becomes more straightforward.