DEV Community

David Quick
David Quick

Posted on

Learn the useState hook by example

In this guide, we'll take a look into useState by comparing class and function components.

This isn't an in-depth look as there are other great features of the useState hook that aren't included in this guide.

What Are Hooks?

React hooks are functions that allow us to access state and lifecycle methods in functional components without having to write a class component.

Prior to hooks, the only way to access the state was by using a class component. Functional components were purposed for handling anything UI related without logic. You may have heard them called "stateless functional components" or "presentational components".

Let's Dive In

I've created a small project that displays two planets using React Kawaii. For the given planets, you can toggle their mood by clicking the Emotion Toggle button.

Class Component

import React, { Component } from 'react';
import { Planet } from 'react-kawaii';

class PlanetClass extends Component {

  state = {
    emotion: true
  }

  handleToggle = () => {
    this.setState(prevState => ({
      emotion: !prevState.emotion
    }))
  }

  render() {
    const { emotion } = this.state
    const emotionCondition = emotion ? 'blissful' : 'ko'

    return (
      <>
        {<Planet size={250} mood={emotionCondition} color="#FDA7DC" />}
        <button
          className='emotion-btn'
          onClick={this.handleToggle}
        >
          Emotion Toggle
        </button>
      </>
    )
  }
}

export default PlanetClass
Enter fullscreen mode Exit fullscreen mode

Above, our component has a single state named emotion with an initial value of "true". Following this, we have a method called handleToggle that takes the initial state and provides the opposite.

The handleToggle method then gets attached to the onClick event handler within our button, allowing us to click the button and toggle between the emotionCondition.

The emotionCondition is a condition that takes the initial state of emotion: true and provides a property of "blissful" if true otherwise "ko" if false.

Please note that I've used the Class Fields syntax in this class component. This allows me to write property instances directly within the class and eliminates the need to create a constructor and call super (my favorite). If you want to learn more about the Class Fields syntax, I'd highly suggest reading this article by Tyler Mcginnis.

I am also using an arrow function for the handleToggle method to avoid binding methods in the constructor since arrow functions have their own "this".

Functional Component

import React, { useState } from 'react';
import { Planet } from 'react-kawaii';

const PlanetHook = () => {
  const [emotion, setEmotion] = useState(true)

  const handleToggle = () => {
    setEmotion(prevState => !prevState)
  }

  const emotionCondition = emotion ? 'blissful' : 'ko'

  return (
    <>
      {<Planet size={250} mood={emotionCondition} color="#61DDBC" />}
      <button
        className='emotion-btn'
        onClick={handleToggle}
      >
        Emotion Toggle
        </button>
    </>
  )
}

export default PlanetHook
Enter fullscreen mode Exit fullscreen mode

At first, you'll notice our functional component using hooks has significantly less code (rubs hands together).

Let's break this down and go over the changes while comparing what we had before.

Within the first line, we've imported useState as a named export from 'react'.

import React, { useState } from 'react';
Enter fullscreen mode Exit fullscreen mode

Let's move down to line five where we've called useState.

  const [emotion, setEmotion] = useState(true)
Enter fullscreen mode Exit fullscreen mode

This single line is what makes our function stateful.

We have two elements within an array, emotion and setEmotion. Both are being destructured (array destructuring) and will be the return value of useState. Within the parenthesis of useState, we store the initial value of our state.

Confusing? We'll go further.

Within the array the first value will be the name of the state and the second will be the setter for the state. Both can be named anything, but it's common practice to include "set" followed by the state name as the setter (second value).

setEmotion is the equivalent of setState in a class component.

Let's take a quick glance at the state in the class and function component.

// Class Component
state = {
    emotion: true
  }

// Function Component
  const [emotion, setEmotion] = useState(true)
Enter fullscreen mode Exit fullscreen mode

Comparing the two, we have a few things that don't inherently change.

  • state and useState are both keywords that dictate state
  • the name of our state (emotion) remains
  • the value of our state remains

The key differences in useState are:

  • We don't store state within an object literal
  • We use destructuring to name our state and state setter
  • Our state value is written within the parenthesis following the useState keyword

How Do I Set State?

Remember, the second value of the array is the setter. We'll use that when updating state. Check out both methods for the class and function component.

// Class Component
handleToggle = () => {
  this.setState(prevState => ({
    emotion: !prevState.emotion
  }))
}

// Function component
  const handleToggle = () => {
  setEmotion(prevState => !prevState)
}
Enter fullscreen mode Exit fullscreen mode

Above, our class component uses setState followed by an object literal within a callback.

In our function, we call setEmotion with the desired updated state.

Both are using callbacks since we are setting state based on a previous state. Also, setState in React is actually asynchronous. This means that after calling setState, the state variable itself may not change right away so it's best to use a callback.

Is that all?

Of course not, there's always more. For now, I'll see you next time and bring useEffect with me.

Top comments (0)