DEV Community

Jason
Jason

Posted on

An Intro into React Hooks with `useState`

An Intro into React Hooks with useState

First, lets get a baseline.

React hooks allow developers to encapsulate abstract logic that can be re-used in some, a few or many components within a react application. Since state is one of the most cumbersome items to manage within a react application; most react hooks help manage state. In fact, one of the most-used react hooks is called useState and (unsurprisingly) it abstracts the code surrounding using state, allowing the developer to focus more on application functionality and less on the technicalities surrounding creating, modifying, and retrieving state.

Old vs. New

To better understand this, let's take a look at a traditional component built without hooks.

import React from 'react' 
// a Counter component that allows an end-user to increment or decrement a counter 
class Counter extends React.component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }

  // increment the value of the counter, defaulting to increase of 1
  increment(amount = 1){
    this.setState(prevState => {
      return { count: prevState.count + amount }
    })
  }

  // decrement the value of the counter, defaulting to a decrement of 1
  decrement(amount = 1){
    this.setState(prevState => {
      return { count: prevState.count - amount }
    })
  }

  // reset the counter to the initial state 
  reset() {
    this.setState({ count: 0 })
  }

  render() {
    return (
      <div>
        <span>{this.state.count}</span>
        <button onClick={ e => increment() }>+</button>
        <button onClick={ e => decrement() }>-</button>
        <button onClick={ e => reset() }>Reset</button>
      </div>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

The code above demonstrates a traditional react component built with class-based inheritance. With hooks, we can transition this code to a more functional approach, with less "boiler-plate" code.

import React, { useState } from 'react' 

function Counter (props) {
  const [value, setValue] = useState(0)

  function increment(amount = 1){
    setValue(value + amount)
  }

  function decrement(amount = 1){
    setValue(value - amount)
  }

  function reset(){
    setValue(0)
  }

  return (
      <div>
        <span>{this.state.count}</span>
        <button onClick={ e => increment() }>+</button>
        <button onClick={ e => decrement() }>-</button>
        <button onClick={ e => reset() }>Reset</button>
      </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

Getting started

The first thing that changes, is that inherently, functions are stateless. In order to circumvent this limitation hooks offload that task to a seperate function: useState.

So first we must import useState from the React library:

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

Now instead of setting the initial state in the constructor of the component (functional components do not have constructors), we set state in the constructor of the useState hook: useState(initialValue).

// old 
class Counter extends React.component {
  constructor(props) {
    super(props)
    this.state = { count: 0 } // providing initial value 
  }
}
// new 
import { useState } from 'react'
function Counter(props){
  const [count, setCount] = useState(0) // providing initial value
}
Enter fullscreen mode Exit fullscreen mode

Unlike class-based state, state using hooks can be of any data type (recall that class-based components are hashes).

Mutating State

The useState hook returns two variables to the caller:

  1. a variable that can be used to access the current state.
  2. a function that can be used to mutate state.

It is up to the developer to name the returned values accordingly, but by convention it is common to name the returned values as 'value' and 'setValue' as [value, setValue] or in the case of our Counter component: [count, setCount].

When we want to change state, we have a couple options:

  1. We can directly modify the state, in which we use the setValue function returned by useState to mutate the value.
  2. We can provide a function that mutates the state, in which the function recieves (as an argument) the previous state and the output of that function is the new state.

This would be contrasted with the component based approach, where we must use a function that recieves the previous state as the argument and returns the new state:

// Component based approach 
increment(amount = 1){
  this.setState(prevState => {
    return { count: prevState.count + amount }
  })
}
Enter fullscreen mode Exit fullscreen mode

So with hooks, we could do the same thing:

// functional approach mirroring the component based approach 
function increment(amount = 1){
  setCount(previousCount => { 
    return previousCount + 1
  })
} 
// or (shorthand)
function increment(amount = 1){
  setCount(previousCount => previousCount + 1)
} 
Enter fullscreen mode Exit fullscreen mode

But with functional components we could simplify this even more:

function increment(amount = 1){
  setCount(count + 1)
} 
Enter fullscreen mode Exit fullscreen mode

Since we already have the current count in memory, all we have to do is access that and implement the same logic, since whatever is placed in the setCount function will be the new value for state.

The Gotchas

With class-based state, we typically store data in a hash, we then copy and modify the state in order to mutate it. While we could do this with the useState hook, it is not recomended. Instead, it is more efficient (and likely more readable) to place each piece of state in seperate state variables:

//incorrect: 
const [state, setState] = useState({ count: 0, color: 'blue'})

// correct 
const [count, setCount] = useState(0)
const [color, setColor] = useState('blue') 
Enter fullscreen mode Exit fullscreen mode

Why?

This would be best answered by reviewing an example; imaginge we had a component that needed to manage states including count and color... To change the color of the component with class-based components we would:

function changeColor(newColor){
  this.setState(previousState => {
    // copy previous state and overwrite color attribute 
    return {...previousState, color: newColor }
  })
}
Enter fullscreen mode Exit fullscreen mode

In functional components, leveraging the useState hook, it would look like:

function changeColor(newColor) {
  setColor(newColor)
}
Enter fullscreen mode Exit fullscreen mode

So why would we use hooks instead of classes?

  1. When you update state, it is more clear what is changing
  2. The syntax is more readable and concise
  3. It is more effecient ( we are not repeatably copying and overwritting data)

Summary

Woah, I know that could be a lot to grasp at once, so here are the key take aways:

  1. React hooks abstract functionality that would typically require a class-based component into a function that can be used in any component within a React application.
  2. The useState hook allows us to more simply manage state than the traditional class-based approach.
  3. If there are multiple pieces of state to be modified, those should be seperated into seperate pieces of state with their own accessor and setter.

Top comments (2)

Collapse
 
shehababouelhassan profile image
shehabAbouelhassan

please I need your help with the implementation of that functionality ! I'm still new to react only couple or weeks I'm coming from pure elementary UI -html/css and PHP - I have attached you a screenshot of the Figma design

with all due respect, I have read this documentation before still dumb enough and not experienced to figure out the solution on my own! .. and i can't refactor the code the meet such functionality!.
reactjs.org/docs/hooks-state.html
in the paint text file I have attached the complete code for that component

I know that I should Start the state with mood value null, and conditionally render the next button if it is not null
When I click on a face, set mood state to a value

so please either try refactoring the code to the best you could or refer me to some tutorial that might of a straight need to help me out with that matter !

Collapse
 
shehababouelhassan profile image
shehabAbouelhassan

is there any way that i can share the code for that component with you for further discussion and assistance !?