useHooks.iov4.1.2
DocsBlogGitHub
Hooks
No hooks found in any category.

useSet

state

Installation

npx usehooks-cli@latest add use-set

Description

A React hook that provides a stateful Set with comprehensive methods for manipulation. Offers all standard Set operations plus additional utilities like filtering, set operations, and array conversion.

Parameters

NameTypeDefaultDescription
initialValues?T[] | Set<T>-Initial values for the Set (array or existing Set)

Return Type

UseSetReturn<T>
PropertyTypeDescription
setSet<T>The current Set instance
add(value: T) => voidAdd a single value to the Set
addMultiple(...values: T[]) => voidAdd multiple values to the Set
remove(value: T) => booleanRemove a value from the Set, returns true if removed
removeMultiple(...values: T[]) => voidRemove multiple values from the Set
clear() => voidRemove all values from the Set
has(value: T) => booleanCheck if the Set contains a value
toggle(value: T) => voidAdd value if not present, remove if present
replace(oldValue: T, newValue: T) => booleanReplace an old value with a new value
filter(predicate: (value: T) => boolean) => voidFilter the Set based on a predicate function
union(otherSet: Set<T> | T[]) => voidAdd all values from another Set or array
intersection(otherSet: Set<T> | T[]) => voidKeep only values that exist in both Sets
difference(otherSet: Set<T> | T[]) => voidRemove values that exist in another Set
isSubsetOf(otherSet: Set<T> | T[]) => booleanCheck if this Set is a subset of another
isSupersetOf(otherSet: Set<T> | T[]) => booleanCheck if this Set is a superset of another
toArray() => T[]Convert the Set to an array
reset() => voidReset the Set to its initial values
sizenumberCurrent number of values in the Set
isEmptybooleanWhether the Set is empty

Examples

Managing a Set of tags

1import { useSet } from '@usehooks.io/use-set'; 2 3function TagManager() { 4 const { 5 set: tags, 6 add, 7 remove, 8 toggle, 9 clear, 10 has, 11 size, 12 isEmpty, 13 toArray 14 } = useSet(['react', 'typescript']); 15 16 return ( 17 <div> 18 <p>Tags ({size}): {isEmpty ? 'None' : toArray().join(', ')}</p> 19 20 <button onClick={() => add('javascript')}> 21 Add JavaScript 22 </button> 23 24 <button onClick={() => toggle('vue')}> 25 Toggle Vue 26 </button> 27 28 <button onClick={() => remove('react')}> 29 Remove React 30 </button> 31 32 <button onClick={clear}> 33 Clear All 34 </button> 35 36 <p>Has React: {has('react') ? 'Yes' : 'No'}</p> 37 </div> 38 ); 39}

Dependencies

react

Notes

  • Optimizes re-renders by only updating state when Set actually changes
  • Supports both Set and array inputs for set operations
  • All methods are memoized with useCallback for performance
  • Maintains referential equality when possible to prevent unnecessary re-renders

Implementation

1"use client"; 2 3import { useState, useCallback } from "react"; 4 5interface UseSetReturn<T> { 6 set: Set<T>; 7 add: (value: T) => void; 8 addMultiple: (...values: T[]) => void; 9 remove: (value: T) => boolean; 10 removeMultiple: (...values: T[]) => void; 11 clear: () => void; 12 has: (value: T) => boolean; 13 toggle: (value: T) => void; 14 replace: (oldValue: T, newValue: T) => boolean; 15 filter: (predicate: (value: T) => boolean) => void; 16 union: (otherSet: Set<T> | T[]) => void; 17 intersection: (otherSet: Set<T> | T[]) => void; 18 difference: (otherSet: Set<T> | T[]) => void; 19 isSubsetOf: (otherSet: Set<T> | T[]) => boolean; 20 isSupersetOf: (otherSet: Set<T> | T[]) => boolean; 21 toArray: () => T[]; 22 reset: () => void; 23 size: number; 24 isEmpty: boolean; 25} 26 27export function useSet<T>(initialValues?: T[] | Set<T>): UseSetReturn<T> { 28 const [set, setSet] = useState<Set<T>>(() => { 29 if (initialValues instanceof Set) { 30 return new Set(initialValues); 31 } 32 return new Set(initialValues || []); 33 }); 34 35 const add = useCallback((value: T) => { 36 setSet((prev) => { 37 if (prev.has(value)) return prev; 38 const newSet = new Set(prev); 39 newSet.add(value); 40 return newSet; 41 }); 42 }, []); 43 44 const addMultiple = useCallback((...values: T[]) => { 45 setSet((prev) => { 46 const newSet = new Set(prev); 47 let hasChanges = false; 48 values.forEach((value) => { 49 if (!newSet.has(value)) { 50 newSet.add(value); 51 hasChanges = true; 52 } 53 }); 54 return hasChanges ? newSet : prev; 55 }); 56 }, []); 57 58 const remove = useCallback((value: T): boolean => { 59 let wasRemoved = false; 60 setSet((prev) => { 61 if (!prev.has(value)) { 62 wasRemoved = false; 63 return prev; 64 } 65 const newSet = new Set(prev); 66 wasRemoved = newSet.delete(value); 67 return newSet; 68 }); 69 return wasRemoved; 70 }, []); 71 72 const removeMultiple = useCallback((...values: T[]) => { 73 setSet((prev) => { 74 const newSet = new Set(prev); 75 let hasChanges = false; 76 values.forEach((value) => { 77 if (newSet.delete(value)) { 78 hasChanges = true; 79 } 80 }); 81 return hasChanges ? newSet : prev; 82 }); 83 }, []); 84 85 const clear = useCallback(() => { 86 setSet((prev) => (prev.size === 0 ? prev : new Set())); 87 }, []); 88 89 const has = useCallback( 90 (value: T): boolean => { 91 return set.has(value); 92 }, 93 [set] 94 ); 95 96 const toggle = useCallback((value: T) => { 97 setSet((prev) => { 98 const newSet = new Set(prev); 99 if (newSet.has(value)) { 100 newSet.delete(value); 101 } else { 102 newSet.add(value); 103 } 104 return newSet; 105 }); 106 }, []); 107 108 const replace = useCallback((oldValue: T, newValue: T): boolean => { 109 let wasReplaced = false; 110 setSet((prev) => { 111 if (!prev.has(oldValue)) { 112 wasReplaced = false; 113 return prev; 114 } 115 const newSet = new Set(prev); 116 newSet.delete(oldValue); 117 newSet.add(newValue); 118 wasReplaced = true; 119 return newSet; 120 }); 121 return wasReplaced; 122 }, []); 123 124 const filter = useCallback((predicate: (value: T) => boolean) => { 125 setSet((prev) => { 126 const newSet = new Set<T>(); 127 let hasChanges = false; 128 prev.forEach((value) => { 129 if (predicate(value)) { 130 newSet.add(value); 131 } else { 132 hasChanges = true; 133 } 134 }); 135 return hasChanges ? newSet : prev; 136 }); 137 }, []); 138 139 const union = useCallback( 140 (otherSet: Set<T> | T[]) => { 141 const otherValues = Array.isArray(otherSet) 142 ? otherSet 143 : Array.from(otherSet); 144 addMultiple(...otherValues); 145 }, 146 [addMultiple] 147 ); 148 149 const intersection = useCallback((otherSet: Set<T> | T[]) => { 150 const otherSetInstance = Array.isArray(otherSet) 151 ? new Set(otherSet) 152 : otherSet; 153 setSet((prev) => { 154 const newSet = new Set<T>(); 155 prev.forEach((value) => { 156 if (otherSetInstance.has(value)) { 157 newSet.add(value); 158 } 159 }); 160 return newSet.size !== prev.size ? newSet : prev; 161 }); 162 }, []); 163 164 const difference = useCallback((otherSet: Set<T> | T[]) => { 165 const otherSetInstance = Array.isArray(otherSet) 166 ? new Set(otherSet) 167 : otherSet; 168 setSet((prev) => { 169 const newSet = new Set<T>(); 170 let hasChanges = false; 171 prev.forEach((value) => { 172 if (!otherSetInstance.has(value)) { 173 newSet.add(value); 174 } else { 175 hasChanges = true; 176 } 177 }); 178 return hasChanges ? newSet : prev; 179 }); 180 }, []); 181 182 const isSubsetOf = useCallback( 183 (otherSet: Set<T> | T[]): boolean => { 184 const otherSetInstance = Array.isArray(otherSet) 185 ? new Set(otherSet) 186 : otherSet; 187 for (const value of set) { 188 if (!otherSetInstance.has(value)) { 189 return false; 190 } 191 } 192 return true; 193 }, 194 [set] 195 ); 196 197 const isSupersetOf = useCallback( 198 (otherSet: Set<T> | T[]): boolean => { 199 const otherSetInstance = Array.isArray(otherSet) 200 ? new Set(otherSet) 201 : otherSet; 202 for (const value of otherSetInstance) { 203 if (!set.has(value)) { 204 return false; 205 } 206 } 207 return true; 208 }, 209 [set] 210 ); 211 212 const toArray = useCallback((): T[] => { 213 return Array.from(set); 214 }, [set]); 215 216 const reset = useCallback(() => { 217 const initialSet = 218 initialValues instanceof Set 219 ? new Set(initialValues) 220 : new Set(initialValues || []); 221 setSet(initialSet); 222 }, [initialValues]); 223 224 return { 225 set, 226 add, 227 addMultiple, 228 remove, 229 removeMultiple, 230 clear, 231 has, 232 toggle, 233 replace, 234 filter, 235 union, 236 intersection, 237 difference, 238 isSubsetOf, 239 isSupersetOf, 240 toArray, 241 reset, 242 size: set.size, 243 isEmpty: set.size === 0, 244 }; 245} 246 247export default useSet; 248