Merge pull request #826 from stefanbugge/pr/816-fix-actions-not-stable-across-renders

fix(useMap): methods with side effects should be stable across renders.
This commit is contained in:
Vadim Dalecky 2019-12-09 06:07:18 -08:00 committed by GitHub
commit 7cf955d6ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 6 deletions

View File

@ -1,18 +1,20 @@
import { useState, useMemo } from 'react';
import { useState, useMemo, useCallback } from 'react';
export interface Actions<T extends object> {
get: <K extends keyof T>(key: K) => T[K];
export interface StableActions<T extends object> {
set: <K extends keyof T>(key: K, value: T[K]) => void;
remove: <K extends keyof T>(key: K) => void;
reset: () => void;
}
export interface Actions<T extends object> extends StableActions<T> {
get: <K extends keyof T>(key: K) => T[K];
}
const useMap = <T extends object = any>(initialMap: T = {} as T): [T, Actions<T>] => {
const [map, set] = useState<T>(initialMap);
const utils = useMemo<Actions<T>>(
const stableActions = useMemo<StableActions<T>>(
() => ({
get: key => map[key],
set: (key, entry) => {
set(prevMap => ({
...prevMap,
@ -27,9 +29,14 @@ const useMap = <T extends object = any>(initialMap: T = {} as T): [T, Actions<T>
},
reset: () => set(initialMap),
}),
[map, set]
[set]
);
const utils = {
get: useCallback(key => map[key], [map]),
...stableActions,
} as Actions<T>;
return [map, utils];
};

View File

@ -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);
});