In React, managing state is a fundamental aspect of building interactive and dynamic user interfaces. The useState()
hook provides a simple and efficient way to manage state in functional components. While it's common to use primitive values or objects as state in React, you can also leverage more complex data structures like sets.
To learn more about using sets with useState()
, you can go through the following basics:
Sets are a built-in data structure in JavaScript that store unique values. They can be particularly useful when you need to manage a collection of distinct items without worrying about duplicates. Integrating sets with the React useState()
hook allows you to maintain such collections within React components.
Initializing useState()
With Set
To use a Set
with useState()
, you can initialize the state with a new instance of a Set
, for example, like so:
// initialize state with a new `Set` instance
const [mySet, setMySet] = useState(new Set());
This sets up the initial state to be an empty Set
, ready to be populated with values as needed.
Adding and Removing Items
To add or remove items from a Set
, you'll typically define functions that use the setter function provided by useState()
. It's crucial to use the updater function form to ensure that you're working with the most up-to-date state, as React may batch state
updates for performance reasons.
For example, to add a new value to the Set
you can do the following:
const addItemToSet = (item) => {
setMySet((prevSet) => {
// 1: create a new `Set` based on the previous `Set`
const newSet = new Set(prevSet);
// 2: add the item to the new `Set`
newSet.add(item);
// 3: return the new `Set`
return newSet;
});
};
In this example, a new Set
is created based on the Set
from the previous render. To remove an item, you can do something similar, as shown below:
const removeItemFromSet = (item) => {
setMySet((prevSet) => {
// 1: create a new `Set` based on the previous `Set`
const newSet = new Set(prevSet);
// 2: remove the item from the new `Set`
newSet.delete(item);
// 3: return the new `Set`
return newSet;
});
};
Why Does a New Set
Need to be Created Each Time?
This approach is beneficial for the following reasons:
- Immutability: React encourages immutability in state management. By creating a new
Set
each time, you're not mutating the existing state directly. This helps prevent unintended side effects by improving code readability and predictability, leading to easier maintenance and debugging. - State Updates: React uses reference equality to detect changes in state. If you modify the existing
Set
directly (for example, by calling add or delete on the currentSet
), React may not detect the change because the reference to theSet
remains the same. By creating a newSet
, you ensure that the reference changes, signaling to React that the state has been updated — you can see this demonstrated in theuseEffect()
hook used in the example. - Functional Updates: React's state updater functions (like
setState
in class components and the updater function returned byuseState()
in functional components) are designed to work with immutable updates. They accept either a new state value or a function that returns the new state based on the previous state. By providing a function that creates a newSet
based on the previousSet
, you adhere to this functional update pattern.
While creating a new Set
every time may seem inefficient, modern JavaScript engines are optimized for such operations, and the performance impact is typically negligible for most applications. Additionally, the benefits of immutability and predictable state management outweigh any minor performance considerations.
Rendering Set
Contents
To display the contents of the Set
in your component, you can, for example, use the Array.from()
method to convert the Set
to an array, and then iterate over it using Array.prototype.map()
:
<div>
{Array.from(mySet).map((item) => (
<div key={item}>{item}</div>
))}
</div>
Example
You can view the complete working example below:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [mySet, setMySet] = useState(new Set());
useEffect(() => {
console.log('Set was updated', mySet);
}, [mySet]);
const addItemToSet = (item) => {
setMySet((prevSet) => {
const newSet = new Set(prevSet);
newSet.add(item);
return newSet;
});
};
const removeItemFromSet = (item) => {
setMySet((prevSet) => {
const newSet = new Set(prevSet);
newSet.delete(item);
return newSet;
});
};
return (
<div>
<button onClick={() => addItemToSet('foo')}>Add Foo</button>
<button onClick={() => addItemToSet('bar')}>Add Bar</button>
<button onClick={() => removeItemFromSet('foo')}>Remove Foo</button>
<button onClick={() => removeItemFromSet('bar')}>Remove Bar</button>
<div>
{Array.from(mySet).map((item) => (
<div key={item}>{item}</div>
))}
</div>
</div>
);
}
export default MyComponent;
In this example:
- The state "
mySet
" is initialized to an emptySet
usinguseState()
; - The "
addItemToSet()
" and "removeItemFromSet()
" functions are defined to add and remove values from theSet
respectively; - These add/remove functions create a copy of the current
Set
, perform the necessary operation (i.e., adding or removing), and then update the state with the newSet
using "setMySet()
"; - In the JSX, the buttons call
addItemToSet()
andremoveItemFromSet()
functions to demonstrate adding and removing values from the set; - Lastly,
Array.from()
is used to convertSet
to array to iterate over it and render its values.
This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.