React 101: Hooks — Part 1

Henna Singh
5 min readMay 9, 2023

Hooks are important in React as they help to make interactive and dynamic web applications.

Previously in React 101 series, I have written about managing static applications. To make an application interactive, React components need variables of their own. These variables (state) are managed by React Hooks. Using Hooks, we can determine what we want to show the users by declaring how our user interface should look based on the state.

React offers a number of built-in Hooks. A few of these include useState(), useEffect(), useContext(), useReducer(), and useRef(). See the full list in the React docs.

Props v/s State

Props” refers to the properties being passed into a component in order for it to work correctly, similar to how a function receives parameters. A component receiving props is not allowed to modify those props i.e. props are immutable.

State” refers to values that are defined within the component and managed by it, similar to variables declared inside a function. Any time you have changing values that should be saved/displayed, you will likely be using state. The state is mutable.

When would you want to use props instead of state?

Anytime you want to pass data into a component so that component can determine what will get displayed on the screen.

When would you want to use state instead of props?

Anytime you want a component to maintain some values from within the component and “remember” those values even when React re-renders the component.

State Hook

A State Hook is the most common Hook used for building React components. It is a named export from the React library, and is imported like this:

import React, {useState} from 'react'

If we console.log(useState()) and console.log(useState("Hello")) , we get an array back with two values.

[undefined, f()]

//and

["Hello", f()]
  • The current state: The current value of this state. The first time it was undefined and the second time a string was passed.
  • The state setter: A function that we can use to update the value of this state.

These two values can be used to track the current state of a data value and change it as needed. The array values can be stored in local variables using array destructuring.

//Destructing
const [currentState, setCurrentState] = useState("Hello")

console.log(currentState) // Hello

Changing State

The value of the state can be changed using the setter function returned by calling useState :

import React, { useState } from "react";

function Toggle() {

const [toggle, setToggle] = useState();

return (
<div>
<p>The toggle is {toggle}</p>
<button onClick={() => setToggle("On")}>On</button>
<button onClick={() => setToggle("Off")}>Off</button>
</div>
);
}

The setter function setToggle is called by onClick event listeners. The value of toggle variable is updated and the component is re-rendered with the new state value.

With the State Hook, updating the state is as simple as calling a state setter function. Calling the state setter signals to React that the component needs to re-render, so the whole function defining the component is called again.

The magic of useState() is that it allows React to keep track of the current value of the state from one render to the next!

Initialize State

A State Hook can be used to manage the value of any primitive data type and even data collections like arrays and objects.

In the following snippet, no initial value is passed, so the value of isLoading variable will be undefined if you log on the console:

import React, { useState } from 'react';

function ToggleLoading() {
const [isLoading, setIsLoading] = useState();

return (
<div>
<p>The data is {isLoading ? 'Loading' : 'Not Loading'}</p>
<button onClick={() => setIsLoading(true)}>
Turn Loading On
</button>
<button onClick={() => setIsLoading(false)}>
Turn Loading Off
</button>
</div>
);
}

A value is passed as an argument to useState() function call to initialize the value of the state.

const [isLoading, setIsLoading] = useState(true);
  1. During the first render, the initial state argument is used.
  2. When the state setter is called, React ignores the initial state argument and uses the new value.
  3. When the component re-renders for any other reason, React continues to use the same value from the previous render.

Note: if you ever need the old value of state to help you determine the new value of state, you should pass a callback function to your state setter function instead of using the state directly. This callback function will receive the old value of state as its parameter, which you can then use to determine your new value of state.

Whenever you don’t need the previous value of the state to determine what the new value of the state should be, you can set the new value as it's done in the previous example.

Set from Previous State

React state updates are asynchronous. Directly making changes to the current state is not recommended. It is a best practice to update a state with a callback function, preventing accidentally outdated values.

In the following code, when the button is pressed, the increment() event handler is called. Inside this function, setCount() , state setter function is used with a callback function.

The callback function gives access to the previous value that can be updated, instead of directly updating the current state — count variable.

import React, { useState } from 'react';

export default function Counter() {
const [count, setCount] = useState(0);

const increment = () => setCount(prevCount => prevCount + 1);

return (
<div>
<p>Wow, you've clicked that button: {count} times</p>
<button onClick={increment}>Click here!</button>
</div>
);
}

Code Snippet for a QuizNavBar

A small quiz application to practice the use of State Hook.

Creating a state for quiz questions:

  const [questionIndex, setQuestionIndex] = useState(0);

Quiz event handlers, so that they call the setter function of the state.

  // define event handlers 
const goBack = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex -1);

const goToNext = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex + 1);

Adding Event Handlers to the Navbar Component.

As JavaScript Arrays use zero-based indexing, the questionIndexis added 1 to number it correctly or the initial state value can be set to 1.

  return (
<nav>
<span>Question #{questionIndex + 1}</span>
<div>
<button onClick={goBack}>
Go Back
</button>
<button onClick={goToNext}>
Next Question
</button>
</div>
</nav>
);

To determine the first and last questions to disable click on the buttons:

  const onFirstQuestion = questionIndex === 0

const onLastQuestion = questionIndex === questions.length - 1;

The complete application using State Hook will be:

mport React, { useState } from 'react';

export default function QuizNavBar({ questions }) {
const [questionIndex, setQuestionIndex] = useState(0);

// define event handlers
const goBack = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex -1);

const goToNext = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex + 1);

// determine if on the first question or not
const onFirstQuestion = questionIndex === 0

const onLastQuestion = questionIndex === questions.length - 1;

return (
<nav>
<span>Question #{questionIndex + 1}</span>
<div>
<button onClick={goBack} disabled={onFirstQuestion}>
Go Back
</button>
<button onClick={goToNext} disabled={onLastQuestion}>
Next Question
</button>
</div>
</nav>
);
}

In the next topic, I will write about Arrays and Objects in State, and how to pass them to other components. Stay Tuned!

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Henna Singh
Henna Singh

Written by Henna Singh

Technical Speaker and an aspiring writer with avid addiction to gadgets, meet-up groups, and paper crafts. Currently doing Full Stack Diploma at Code Institute

No responses yet

Write a response