mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 10:20:09 +02:00
fix(theme-common): add a missing generic constraint (#7648)
This commit is contained in:
parent
7b239e2ec5
commit
51d7899b0d
2 changed files with 34 additions and 21 deletions
|
@ -27,9 +27,12 @@ describe('useShallowMemoObject', () => {
|
||||||
const someArray = ['hello', 'world'];
|
const someArray = ['hello', 'world'];
|
||||||
|
|
||||||
const obj1 = {a: 1, b: '2', someObj, someArray};
|
const obj1 = {a: 1, b: '2', someObj, someArray};
|
||||||
const {result, rerender} = renderHook((val) => useShallowMemoObject(val), {
|
const {result, rerender} = renderHook<object, object>(
|
||||||
|
(val) => useShallowMemoObject(val),
|
||||||
|
{
|
||||||
initialProps: obj1,
|
initialProps: obj1,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
expect(result.current).toBe(obj1);
|
expect(result.current).toBe(obj1);
|
||||||
|
|
||||||
const obj2 = {a: 1, b: '2', someObj, someArray};
|
const obj2 = {a: 1, b: '2', someObj, someArray};
|
||||||
|
@ -40,17 +43,31 @@ describe('useShallowMemoObject', () => {
|
||||||
rerender(obj3);
|
rerender(obj3);
|
||||||
expect(result.current).toBe(obj1);
|
expect(result.current).toBe(obj1);
|
||||||
|
|
||||||
// Current implementation is basic and sensitive to order
|
|
||||||
const obj4 = {b: '2', a: 1, someObj, someArray};
|
const obj4 = {b: '2', a: 1, someObj, someArray};
|
||||||
rerender(obj4);
|
rerender(obj4);
|
||||||
expect(result.current).toBe(obj4);
|
expect(result.current).toBe(obj1);
|
||||||
|
|
||||||
const obj5 = {b: '2', a: 1, someObj, someArray};
|
const obj5 = {b: '2', a: 1, someObj, someArray};
|
||||||
rerender(obj5);
|
rerender(obj5);
|
||||||
expect(result.current).toBe(obj4);
|
expect(result.current).toBe(obj1);
|
||||||
|
|
||||||
const obj6 = {b: '2', a: 1, someObj: {...someObj}, someArray};
|
const obj6 = {b: 1, a: '2', someObj, someArray};
|
||||||
rerender(obj6);
|
rerender(obj6);
|
||||||
expect(result.current).toBe(obj6);
|
expect(result.current).toBe(obj6);
|
||||||
|
expect(result.current).not.toBe(obj5);
|
||||||
|
|
||||||
|
const obj7 = {b: 1, a: '2', someObj: {...someObj}, someArray};
|
||||||
|
rerender(obj7);
|
||||||
|
expect(result.current).toBe(obj7);
|
||||||
|
expect(result.current).not.toBe(obj6);
|
||||||
|
|
||||||
|
const obj8 = {...obj7};
|
||||||
|
rerender(obj8);
|
||||||
|
expect(result.current).toBe(obj7);
|
||||||
|
|
||||||
|
const obj9 = {...obj7, another: true};
|
||||||
|
rerender(obj9);
|
||||||
|
expect(result.current).toBe(obj9);
|
||||||
|
expect(result.current).not.toBe(obj7);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,21 +76,17 @@ export class ReactContextError extends Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shallow-memoize an object
|
* Shallow-memoize an object. This means the returned object will be the same as
|
||||||
*
|
* the previous render if the property keys and values did not change. This
|
||||||
* This means the returned object will be the same as the previous render
|
* works for simple cases: when property values are primitives or stable
|
||||||
* if the attribute names and identities did not change.
|
* objects.
|
||||||
*
|
|
||||||
* This works for simple cases: when attributes are primitives or stable objects
|
|
||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
export function useShallowMemoObject<O>(obj: O): O {
|
export function useShallowMemoObject<O extends object>(obj: O): O {
|
||||||
return useMemo(
|
const deps = Object.entries(obj);
|
||||||
() => obj,
|
// Sort by keys to make it order-insensitive
|
||||||
// Is this safe?
|
deps.sort((a, b) => a[0].localeCompare(b[0]));
|
||||||
// TODO make this implementation not order-dependent?
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[...Object.keys(obj), ...Object.values(obj)],
|
return useMemo(() => obj, deps.flat());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue