DEV Community

Cover image for React Hooks Series: useState
James Cox
James Cox

Posted on • Edited on

React Hooks Series: useState

Introduction

I have created a small timer app in Codesandbox:

Timer CodeSandbox

I am attempting to cover A LOT in this series of posts. I have included the link to the Codesandbox, so you are encouraged to fork it and play around with it. But if you don't understand everything quite yet, fear not! I promise to cover every single line of code you see.

These series of articles make a few assumptions: you have some experience with React and understand some of its core features (e.g. virtual DOM, class vs. functional component syntax, state management).

Alright, let's dive in!

Part One - useState

In Part One of my React hooks series, we are going to focus on the useState hook.

Import useState from React

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

React's useState accepts one argument, the initial state and returns a pair of values, the current state and a function to change the state.

 const [input, setInput] = useState(0)
 const [counter, setCounter] = useState(null)
 const [start, setStart] = useState(false)
Enter fullscreen mode Exit fullscreen mode

The intial state of input is 0
The intial state of counter is null
The initial state of start is false

As you can see, the argument passed to useState doesn't have to be an object, it can be a number, or a string, a boolean, etc!

Let's pause for a moment and take a look at a Class component example, which might be helpful to those familiar with the Class syntax.

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: 0,
      counter: null,
      start: false
    };
  }
Enter fullscreen mode Exit fullscreen mode

The Class example does the exact same thing of setting initial state. But, and this my opinion, the useState hook version is much cleaner and easier to read!

Now what?

The current state of input, counter, and start is accessible throughout our functional component and can be used to evaluate expressions and display information in our render() method.

But the REAL POWER is being able to update the state however we please!

Let's focus on creating a form responsible for setting our Timer and the intial values of input and counter:

   <form onSubmit={(e) => handleSubmit(e)}>
        <h1>Timer</h1>
        <input 
          onChange={handleChange} 
          min="0" 
          type="number" 
          id="seconds" 
          placeholder="seconds" 
          style={{textAlign: "center", width: "5rem"}}
        />
        <input type="submit" value="Set Timer"/>
   </form>
Enter fullscreen mode Exit fullscreen mode

Will render on our screen:

Timer form rendered on screen

A couple notes

  • min="0" on a form with a type="number" won't let the user select a number less than zero. Cool, huh?
  • onSubmit={(e) => handleSubmit(e)} and onChange={handleChange} are different ways of writing the same thing. I haven't noticed behavioral differences, so if you are reading this and know the difference, please let me know in the comments!

Let's take a look at those functions, handleChange and handleSubmit:

const handleChange = (e) => {
    setInput(e.target.value)
}
Enter fullscreen mode Exit fullscreen mode
const handleSubmit = (e) => {
    e.preventDefault() // stops the submit from performing a re-render
    setCounter(input)
    e.target.reset() // removes the input from the "seconds" form input
}
Enter fullscreen mode Exit fullscreen mode

Finally! We are using our new fancy hook, useState! inside handleChange we call setInput(e.target.value). This updates the current state to whatever is passed in (isn't it satisfying to watch the number on your screen change as your input changes?). Similarly, we call setCounter(input) inside handleSubmit.

Notice what's happening here: handleChange updates input, and then handleSubmit uses the value of input to set the state of counter with setCounter.

(Some readers might wonder why I have two different states for essentially the same value. Without getting into too many spoilers, it made sense for me to have two different versions of state to conditionally render elements on the screen. The value of input isn't affected by the timer, where as counter will change every second.)

Okay fine, let's talk about one of those conditional renders before we get to the final implementation of useState, setStart.

 {
   start === false && counter !== null && counter !== 0
   ? 
   <button style={{fontSize: "1.5rem"}} onClick={handleStart}>START</button> 
   : 
   null
 }

 {
   start === true && counter !== 0
   ? 
   <button style={{fontSize: "1.5rem"}} onClick={handlePause}>PAUSE</button> 
   : 
   null 
}
Enter fullscreen mode Exit fullscreen mode

There's a lot to unpack here. First, I'm using something called a ternary operator to evaluate a statement, using boolean values.

Ternary operator syntax
condition ? option1 : option2
If condition === true run the statement on the left option1 and if condition === false run the statement on the right option2

In my examples:
First, I set a condition start === false && counter !== null && counter !== 0
If ALL of these conditions are true, run the code on the left:
<button style={{fontSize: "1.5rem"}} onClick={handleStart}>START</button>
If even ONE of these conditions is not true, run the code on the right:
null

It's a very similar situation for the PAUSE button. Basically what's happening is, I only show the START or PAUSE buttons based on certain conditions.

Once the START button is rendered, the user can update or final state start by activating onClick={handleStart}

const handleStart = () => {
    setStart(true)
}
Enter fullscreen mode Exit fullscreen mode

If you recall, the initial state start is false. Here we set start to true and it will stay true until something else changes it.

In the next article in this series we will get to see more calls to setInput, setCounter and setStart as we explore the useRef and useEffect hooks.

Final thoughts

Thank you for reading my first entry in the React Hooks Series! As soon as I have the second entry complete, I will post it and update this post with the link.

If you have any questions, suggestions, corrections or general comments, I WOULD LOVE to read them and hear more from all of you!

THANK YOU AND HAPPY CODING

Top comments (4)

Collapse
 
tlylt profile image
Liu Yongliang

Hey, cool!
Some tips on formatting that you may be interested in:

  • code syntax highlighting can be done if you add the name of the language, in your case e.g. (3 backticks follow by javascript, no space in between)
import React, { useState } from "react";
Collapse
 
jamesncox profile image
James Cox

Thanks! These are some useful tips to know! I’ll see if I can update my post using them later tonight or tomorrow 🙏🙏🙏

Collapse
 
aliakba17883515 profile image
Ali Akbar

kindly share the Role Base Authentication in React, Redux, and Hooks
i am awaiting for this ..

Collapse
 
aliakba17883515 profile image
Ali Akbar

thank to share this react hooks series code