React101: Hooks — Part 2

Henna Singh
5 min readMay 16, 2023

Previously in Hooks-Part1, I introduced the useState hook and how it is used to maintain state values and change them.

In this section, I am exploring more on Arrays and Objects in State and when to use multiple hooks.

Arrays in State

JSX lists are easily rendered by using JavaScript arrays.

import React, { useState } from 'react';

//Static array of pizza options offered.
const options = ['Bell Pepper', 'Sausage', 'Pepperoni', 'Pineapple'];

export default function PersonalPizza() {
const [selected, setSelected] = useState([]);

const toggleTopping = ({target}) => {
const clickedTopping = target.value;
setSelected((prev) => {
// check if clicked topping is already selected
if (prev.includes(clickedTopping)) {
// filter the clicked topping out of state
return prev.filter(t => t !== clickedTopping);
} else {
// add the clicked topping to the state
return [clickedTopping, ...prev];
}
});
};

return (
<div>
{options.map(option => (
<button value={option} onClick={toggleTopping} key={option}>
{selected.includes(option) ? 'Remove ' : 'Add '}
{option}
</button>
))}
<p>Order a {selected.join(', ')} pizza</p>
</div>
);
}

In the above example, there are two arrays:

  • The options array contains the names of all of the pizza toppings available.
  • The selected array represents the selected toppings for our personal pizza.

The options array contains static data, meaning that it does not change. You can define static data models outside of function components since they don’t need to be recreated each time our component re-render.

The selected array contains dynamic data, meaning that it changes, usually based on a user’s actions. The selected variable is initialized as an empty array.

When a button is clicked, the toggleTopping() event handler is called. The event handler uses information from the event object to determine which topping was clicked.

Note: When updating an array in a state, directly updating the state is not recommended. The previous array is replaced with a new array. The information from the previous array is explicitly copied to the new array using spread syntax.

The full code can be found in the code sandbox below:

Objects in State

A set of related variables are grouped into objects and can be used in a state. The following is an example of a login function

export default function Login() {

const [formState, setFormState] = useState({}); //empty initial state

const handleChange = ({ target }) => {
const { name, value } = target;
setFormState((prev) => ({
...prev,
[name]: value
}));
};

return (
<form>
<input
value={formState.firstName}
onChange={handleChange}
name="firstName"
type="text"
/>
<input
value={formState.password}
onChange={handleChange}
type="password"
name="password"
/>
</form>
);
}
  • A state setter callback function to update the state based on the previous value.
  • The spread syntax is the same for objects as for arrays: { ...oldObject, newKey: newValue }.
  • The event handler is re-used across multiple inputs by using the input tag’s name attribute to identify which input the change event came from.

Anytime, one of the input values is updated, the handleChange() function is called. The object is destructured to unpack name and target properties from the event object.

For updating the state with setFormState() inside the function, spread syntax is used to copy values from the previous object, and the value for the name property is over-written with the new value.

The square brackets around the name is a way to use string value stored by the name variable as a property value. The computed property name allows using dynamically generated names within object literals.

Separate Hooks for Separate States

As the saying goes in the data world- The data that is accessed together should be stored together. Managing dynamic data is easier when we keep data models as simple as possible.

For a complex object like below, it is beneficial to create multiple state variables based on which values tend to change together.

function Subject() {
const [state, setState] = useState({
currentGrade: 'B',
classmates: ['Hasan', 'Sam', 'Emma'],
classDetails: {topic: 'Math', teacher: 'Ms. Barry', room: 201};
exams: [{unit: 1, score: 91}, {unit: 2, score: 88}]);
});

The above example can be simplified by creating multiple hooks. This makes the code more simple to write, read, text, and reuse across components.

function Subject() {
const [currentGrade, setGrade] = useState('B');
const [classmates, setClassmates] = useState(['Hasan', 'Sam', 'Emma']);
const [classDetails, setClassDetails] = useState({topic: 'Math', teacher: 'Ms. Barry', room: 201});
const [exams, setExams] = useState([{unit: 1, score: 91}, {unit: 2, score: 88}]);
// ...
}

Another example of a large state object refactored to make it more readable and reusable:

import React, { useState } from "react";

function Musical() {
const [state, setState] = useState({
title: "Best Musical Ever",
actors: ["George Wilson", "Tim Hughes", "Larry Clements"],
locations: {
Chicago: {
dates: ["1/1", "2/2"],
address: "chicago theater"
},
SanFrancisco: {
dates: ["5/2"],
address: "sf theater"
}
}
})
}

function MusicalRefactored() {

const [title, setTitle] = useState("Best Musical Ever")

const[actors, setActors] = useState(["George Wilson", "Tim Hughes", "Larry Clements"])

const[locations, setLocations] = useState({
Chicago: {
dates: ["1/1", "2/2"],
address: "chicago theater"
},
SanFrancisco: {
dates: ["5/2"],
address: "sf theater"
}
})
}

Review: The State Hook

  • With React, A view is rendered to the screen by feeding static or dynamic data models to JSX.
  • Hooks are used to “hook into” the internal component state for managing dynamic data in function components.
  • For the state hook below, the currentState references the current value of the state and initialState initializes the value of the state for the component’s first render.
const [currentState, stateSetter] = useState( initialState );
  • State setters can be called in the event handlers.
  • The simple event handlers can be defined inline in the JSX and complex event handlers outside of the JSX.
  • A state setter callback function is used when the next value depends on the previous value.
  • Arrays and objects are used to organize and manage related data that tend to change together.
  • The spread syntax is used on collections of dynamic data to copy the previous state into the next state like so: setArrayState((prev) => [ ...prev ]) and setObjectState((prev) => ({ ...prev })).
  • It’s best practice to have multiple, simpler states instead of having one complex state object.

Some code snippets to see useState in action are mentioned in my next article: State Management

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

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