DEV Community

Cover image for Thinking in React Hooks
David Martin
David Martin

Posted on

Thinking in React Hooks

if you haven't already, please read the official docs on React Hooks. What I present here is my take on hooks, what I have found to be a useful explanation.

thinking in hooks

Hooks in React provide a new way of thinking about how your components work. With class components we are used to thinking in terms of the life cycle of the component. Is the component mounting? Has it already mounted? Is it getting updated? Is it leaving us? However, hooks are geared toward the idea that React will synchronize your component with its state.

I find this easier to grasp once I begin thinking of React as more of a templating engine on steroids. Let me draw this out:

Some people may look at JSX as an attempt to bring HTML into JavaScript, but I believe that is only because JSX looks similar to HTML. Instead, think of the JSX as a template. You are telling React that this is the way you want your UI put together, or how you want it to look when it is all said and done. React takes that "template" and runs it through the reactor and out comes DOM elements.

In the process of doing this your state will probably need to come in at some point, and it may change over time.

The entirety of your component is to provide and manage state along with specifying what you want your component to look like, using that state.

Hooks . . .

With React hooks we can think in terms of state changing, and, as a result, how the UI should be affected by those changes.

useState

is the most basic hook. It provides a super simple mechanism for state: the state itself, and a way to change it.

const [state, setState] = React.useState('')

With this code you can use the state variable throughout your component, and use the setState function to change it. React will take care of persisting the value of the state between render calls. The argument you provide to the useState call is simply the initial value. If you are using TypeScript, the type of the state variable will be inferred. You can also explicitly declare the type via generics: const [state, setState] = React.useState<string | null>(null).

useEffect

is the next hook that you will probably use most often. Many times the only two hooks you will need will be useState and useEffect.

useEffect takes two parameters. A function and an array.

Let's start with the array first. The array is a list of things that, when changed, should cause the effect to be run. If they don't change, the effect won't run. These things are variables from your component. They may be pieces of state or props,

The function is where the effect actually lives. This function will be executed when anything in the array changes.

The first thing to note is that the effect will always run once upon start up. This is not optional. It is required because React will do something extra special that first time it runs the effect - it will capture its return value.

This is the second important thing to note. The function you provide for the effect can return something, and that something is important. What you return can be one of two things: undefined or another function. React will use this to cleanup your effect. There is a side "effect" to this requirement: your effect may not be an async function. Why? Async functions return Promises, and the effect can only return undefined or a function. There are ways around this that I will cover later on.

Back to the array. It can be helpful to think of the array as an answer to the question "When should this effect be run?" And there are three possible answers: Once and only once, always, and it depends.

  • Run once: give it an empty list. []
  • Run always: give it no list.
  • It depends: give it a list of things that would cause it to change [props.color, firstName]
React.useEffect(() => {
    console.log('this effect will only run once')

    // and it does nothing to clean up
}, [])

React.useEffect(() => {
    console.log('this effect will run every render')

    return () => {
        console.log('this is run when this effect is cleaned up')
    }
})

React.useEffect(() => {
    console.log('this effect will run the first render, and then only when the first name changes')
}, [firstName])

Top comments (0)