useMap()
This React hook provides an API to interact with a Map
(Documentation)
It takes as initial entries a Map
or an array like [["key": "value"], [..]]
or nothing and returns:
- An array with an instance of
Map
(including:foreach, get, has, entries, keys, values, size
) - And an object of methods (
set, setAll, remove, reset
)
Make sure to use these methods to update the map, a map.set(..)
would not re-render the component.
Why use Map instead of an object ?
Map is an iterable, a simple hash and it performs better in storing large data (Read more).
The Hook
1import { useCallback, useState } from 'react'23export type MapOrEntries<K, V> = Map<K, V> | [K, V][]45// Public interface6export interface Actions<K, V> {7 set: (key: K, value: V) => void8 setAll: (entries: MapOrEntries<K, V>) => void9 remove: (key: K) => void10 reset: Map<K, V>['clear']11}1213// We hide some setters from the returned map to disable autocompletion14type Return<K, V> = [Omit<Map<K, V>, 'set' | 'clear' | 'delete'>, Actions<K, V>]1516function useMap<K, V>(17 initialState: MapOrEntries<K, V> = new Map(),18): Return<K, V> {19 const [map, setMap] = useState(new Map(initialState))2021 const actions: Actions<K, V> = {22 set: useCallback((key, value) => {23 setMap(prev => {24 const copy = new Map(prev)25 copy.set(key, value)26 return copy27 })28 }, []),2930 setAll: useCallback(entries => {31 setMap(() => new Map(entries))32 }, []),3334 remove: useCallback(key => {35 setMap(prev => {36 const copy = new Map(prev)37 copy.delete(key)38 return copy39 })40 }, []),4142 reset: useCallback(() => {43 setMap(() => new Map())44 }, []),45 }4647 return [map, actions]48}4950export default useMap
Usage
1import { Fragment } from 'react'23import { MapOrEntries, useMap } from 'usehooks-ts'45const initialValues: MapOrEntries<string, string> = [['key', '🆕']]6const otherValues: MapOrEntries<string, string> = [7 ['hello', '👋'],8 ['data', '📦'],9]1011export default function Component() {12 const [map, actions] = useMap<string, string>(initialValues)1314 const set = () => actions.set(String(Date.now()), '📦')15 const setAll = () => actions.setAll(otherValues)16 const reset = () => actions.reset()17 const remove = () => actions.remove('hello')1819 return (20 <div>21 <button onClick={set}>Add</button>22 <button onClick={reset}>Reset</button>23 <button onClick={setAll}>Set new data</button>24 <button onClick={remove} disabled={!map.get('hello')}>25 {'Remove "hello"'}26 </button>2728 <pre>29 Map (30 {Array.from(map.entries()).map(([key, value]) => (31 <Fragment key={key}>{`\n ${key}: ${value}`}</Fragment>32 ))}33 <br />)34 </pre>35 </div>36 )37}
See a way to make this page better?
Edit there »