Skip to content

Instantly share code, notes, and snippets.

@nilscox
Created August 31, 2023 08:46
Show Gist options
  • Save nilscox/063cca780bde1e514528a35726affac8 to your computer and use it in GitHub Desktop.
Save nilscox/063cca780bde1e514528a35726affac8 to your computer and use it in GitHub Desktop.
React hook to manipulate a JavaScript Set
import { useReducer, useMemo } from 'react'
type UseSetReturn<T> = [
Set<T>,
{
add: (value: T) => void
delete: (value: T) => void
toggle: (value: T) => void
clear: () => void
}
]
export function useSet<T>(): UseSetReturn<T> {
const [set, dispatch] = useReducer(reducer<T>, new Set<T>())
return [
set,
useMemo(
() => ({
add: (value: T) => dispatch({ type: 'add', value }),
delete: (value: T) => dispatch({ type: 'delete', value }),
toggle: (value: T) => dispatch({ type: 'toggle', value }),
clear: () => dispatch({ type: 'clear' }),
}),
[dispatch]
),
]
}
type UseSetAction<T> =
| { type: 'add'; value: T }
| { type: 'delete'; value: T }
| { type: 'toggle'; value: T }
| { type: 'clear' }
function reducer<T>(set: Set<T>, action: UseSetAction<T>) {
const copy = new Set(set)
if (action.type === 'add') {
copy.add(action.value)
}
if (action.type === 'delete') {
copy.delete(action.value)
}
if (action.type === 'toggle') {
if (copy.has(action.value)) {
copy.delete(action.value)
} else {
copy.add(action.value)
}
}
if (action.type === 'clear') {
copy.clear()
}
return copy
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment