Managing State with React Hooks
Tags: react
Published: 2022-02-01 13:56:25

---
title: Managing State with React Hooks
published: true
date: 2020-08-04 21:35:27 UTC
tags: react
canonical_url: https://sabinadams.hashnode.dev/managing-state-with-react-hooks
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1596576963332/3skT3B65k.png
---

Early last year React 16.8 was released, bringing with it the addition of `hooks`. This introduction of hooks gave developers the ability to take many of the useful features of React (such as Lifecycle Events, Context, and State) available in `class components` and use them inside of `function components`.

In this article we will take a look at a few ways we can use hooks to manage state within function components.

> If you’d like to know more about the How’s and Why’s of using function components with hooks vs. class components, check out [React’s Introduction to Hooks](https://reactjs.org/docs/hooks-intro.html)

_The application built in this tutorial is available on [github](https://github.com/sabinadams/hooks-state-playground)_

* * *

## The `useState` Hook

The `useState` hook allows you to declare state variables in a function component. This data is preserved on re-renders by React exactly like a state variable in a class component is preserved. To use the hook we simply have to import it and call it, passing in an initial value.

Let’s give it a try!

### Declaring a state variable with `useState`

First, let’s declare a state variable named `points` that we will use to hold a numeric point value that will be used by a point counter.

```
import React, { useState } from 'react'
function Points() {
    // Creates a state variable named 'points' whose initial value is 0
   const [points, setPoints] = useState(0)
   // ...

```

As we can see, `useState()` takes one parameter, the variable’s initial value. In this case we set the initial value to 0, however we could have assigned it an Object, Array, String, etc… Whatever you fancy!

The return value of `useState()` is an array containing two items. The first is the most recent value of that state variable. The second is a function used to update that state variable. We use destructuring to grab both of those items out of the return.

### Updating a state variable

Now we can use the `setPoints()` returned by `useState()` to update the `points` state variable!

```
// ...
const [points, setPoints] = useState(0)
return (
    <>
       <button onClick={ () => setPoints( points + 1) }>Add</button>
    </>
)
// ...

```

In the code above, every time the user clicks the Add button, the points state variable will be `incremented` by one.

### Putting it all together

Okay, so now we have a state variable and have the ability to update that variable! Let’s put those things together. Below is the completed Points component. Notice we can call `setPoints()` from within another function in the component, `resetPoints()` in this case.

```
import React, { useState } from 'react'
import '../assets/scss/Points.scss'

function Points() {
  // Creates a state variable named 'points' whose initial value is 0
  const [points, setPoints] = useState(0)
  // Function that will reset the point count
  const resetPoints = () => setPoints(0)

  return (
    <div id="Points">
      <p className="title">Points (useState)</p>
      <hr className="divider"/>
      <div className="pointsContainer">
          <div className="buttons">
            {/* These buttons use the setPoints function to update the state variable's value */}
            <button className="button add" onClick={() => setPoints( points + 1 )}>Add</button>
            <button className="button subtract" onClick={() => setPoints( points - 1 )}>Subtract</button>
            <button className="button reset" onClick={resetPoints}>Reset</button>
          </div>
          <div className="outputBox">
            {/* Output the points variable */}
            <p>{ points }</p>
          </div>
      </div>
    </div>
  );
}

export default Points

```

* * *

![useStateGif-6.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1596575924767/jx7A2cqM6.gif)

Pretty simple stuff, right?

Using hooks, we have successfully set up and updated a state variable within a function component. Now you might be wondering, _“What if I have a really complex state in my component with deeply nested data? Is there a cleaner way to set up the state?“_

In the next section we’ll take a look at an alternative to `useState()` that addresses this exact problem!

* * *

## The `useReducer` Hook

The `useReducer` hook provides the ability to manage state in a way that is very similar to how Redux manages state with reducers and dispatched actions.

> If you aren’t sure what a reducer is, it is basically a function that updates a state based on an action that gets sent to it. For more detailed information, check out [Redux’s documentation on reducers](https://redux.js.org/basics/reducers)

To use `useReducer` we have to import and call it, passing in a reducer and the initial state of the component.

### Setting up the state and reducer with `useReducer`

Let’s start by creating a simple reducer, which will define how to update the state based on certain actions, and tell the component to use that reducer.

```
import React, { useReducer } from 'react'

// The initial state of the component
const initialState = { points: 0 }
// The reducer we are going to use
function reducer( state, action ) {
  switch ( action.type ) {
    case 'add':
      return { points: state.points + 1 };
    default:
      throw new Error();
  }
}

function Points() {
  // Sets up a reducer to handle the state 
  const [state, dispatch] = useReducer( reducer, initialState );
  // ...

```

In the code above, we set up our initial state to be an object with a single key, `points`, whose value is 0. This example is simple, but `useReducer` really shines as the state gets more complex.

The hook takes in a `reducer` as its first argument and the `initial state` as its second argument.

With this all set up, we now have a reducer available to the component that is ready to handle actions and maintain state across re-renders!

> `useReducer` can also take in a third argument, a function that allows you to lazily initialize the state. This can be useful if you would like to calculate the initial state outside of the reducer. Also, because this initialization function is outside of the reducer, it may be used later on to reset the state. See [the docs](https://reactjs.org/docs/hooks-reference.html#lazy-initialization) for more info.

### Dispatching actions to the reducer to update the state

`useReducer()` returns an array with two items. The first being the most current version of the state and the second a `dispatch` function. This function is used exactly the same way it would be in Redux.

```
// ***
return (
    <>
          <button onClick={() => dispatch({type: 'add'})}>Add</button>
    </>
);
// ***

```

When the button is clicked, the `dispatch` function is fired with a type of `add`, which gets caught by the reducer and results in `state.points` being incremented by 1.

### Putting it all together

Awesome! Now let’s put all of that together. Here is a completed component using these concepts.

```
import React, { useReducer } from 'react'
import '../assets/scss/Points.scss'

// The initial state of the component
const initialState = { points: 0 }
// The reducer we are going to use
function reducer( state, action ) {
  switch (action.type) {
    case 'add':
      return { points: state.points + 1 };
    case 'subtract':
      return { points: state.points - 1 };
    case 'reset':
      return { points: 0 }
    default:
      throw new Error();
  }
}

function Points() {
  // Sets up a reducer to handle the state 
  const [state, dispatch] = useReducer( reducer, initialState );

  return (
    <div id="Points">
      <p className="title">Points (useReducer)</p>
      <hr className="divider"/>
      <div className="pointsContainer">
          <div className="buttons">
            {/* These buttons use the dispatch to update the state */}
            <button className="button add" onClick={() => dispatch({type: 'add'})}>Add</button>
            <button className="button subtract" onClick={() => dispatch({type: 'subtract'})}>Subtract</button>
            <button className="button reset" onClick={() => dispatch({type: 'reset'})}>Reset</button>
          </div>
          <div className="outputBox">
            {/* Output the points variable */}
            <p>{ state.points }</p>
          </div>
      </div>
    </div>
  );
}

export default Points

```

* * *

![useReducerGif-1.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1596576685513/mCDT1eOf8.gif)

So there we have it!

A function component using a reducer to manage state. This way of managing state is preferable over `useState` because of some performance boosts that are mentioned in [React’s documentation](https://reactjs.org/docs/hooks-reference.html#usereducer) on the `useReducer` hook.

* * *

## Conclusion

As you can see from the examples above, React’s implementation of hooks has not only brought over the useful feature of statefulness from class components to function components, but has also made it pretty easy to do!

We looked at two ways to keep state in a function component. First, using `useState` and then using `useReducer`. In general, `useReducer` is the way to go when dealing with larger data sets in the state, while `useState` is great for components with a simpler state.

> The next step to this would be sharing state across multiple function components! In my tutorial [Shared State with React Hooks and Context API](https://www.sabinthedev.com/shared-state-with-react-hooks-and-context-api/) I cover one of the more popular ways out there to achieve this. Give it a read if you’re interested!

Thanks for reading, I hope you enjoyed!