diff --git a/src/useMap.ts b/src/useMap.ts index a0c60e96..236ac177 100644 --- a/src/useMap.ts +++ b/src/useMap.ts @@ -1,18 +1,20 @@ -import { useState, useMemo } from 'react'; +import { useState, useMemo, useCallback } from 'react'; -export interface Actions { - get: (key: K) => T[K]; +export interface StableActions { set: (key: K, value: T[K]) => void; remove: (key: K) => void; reset: () => void; } +export interface Actions extends StableActions { + get: (key: K) => T[K]; +} + const useMap = (initialMap: T = {} as T): [T, Actions] => { const [map, set] = useState(initialMap); - const utils = useMemo>( + const stableActions = useMemo>( () => ({ - get: key => map[key], set: (key, entry) => { set(prevMap => ({ ...prevMap, @@ -27,9 +29,14 @@ const useMap = (initialMap: T = {} as T): [T, Actions }, reset: () => set(initialMap), }), - [map, set] + [set] ); + const utils = { + get: useCallback(key => map[key], [map]), + ...stableActions, + } as Actions; + return [map, utils]; }; diff --git a/tests/useMap.test.ts b/tests/useMap.test.ts index 58623f6b..0bcf3e21 100644 --- a/tests/useMap.test.ts +++ b/tests/useMap.test.ts @@ -121,3 +121,17 @@ it('should reset map to initial object provided', () => { expect(result.current[0]).toEqual({ foo: 'bar', a: 1 }); }); + +it('should memoize actions with side effects', () => { + const { result } = setUp({ foo: 'bar', a: 1 }); + const [, utils] = result.current; + const { set, remove, reset } = utils; + + act(() => { + set('foo', 'baz'); + }); + + expect(result.current[1].set).toBe(set); + expect(result.current[1].remove).toBe(remove); + expect(result.current[1].reset).toBe(reset); +});