use-reduce-memo
useReduceMemo is a React Hook that lets you cache the result of a reduce function between re-renders.
Background
useMemo remembers the result of a single operation. This is sometimes insufficient for complex applications. Multiple components could be used to house individual operation, this may not be desirable in some cases.
useReduceMemo is similar to Array.reduce and Iterator.reduce, which perform operations on every element and the result is memoized. In the next render, if the operation has already performed on the same element, it will be skipped.
Demo
Click here for our live demo.
How to use?
The following sample passes an array of [1, 2, 3] to an accumulative reducer. The return is the total sum of all values.
function MyComponent() {
const array = [1, 2, 3];
const accumulator = useCallback((result, value) => value + result, []);
const result = useReduceMemo<number, number>(array, accumulator, 0);
// Would print 6.
return <Fragment>{result}</Fragment>;
}
API
function useReduceMemo<T, U>(
target: readonly T[] | Iterable<T>,
callbackfn: (previousValue: U, currentValue: T, currentIndex: number, target: readonly T[] | Iterable<T>) => U,
initialValue: U
): U;
The API is very similar to Array.reduce and Iterator.reduce. The target must be passed as the first value to the hook.
Notes: callbackfn should be memoized with useCallback or useMemo. If callbackfn is changed, all memoized results will be invalidated.
Design
We started the journey with a memoized mapper hook.
A mapper operates independently on each item, without requiring knowledge of other elements. Thus, in some cases, the mapper can be refactored into multiple components, each with their own call to useMemo. This limits the true utility of a memoized mapper.
In contrast, a memoized reducer could be turned into a memoized mapper. Thus, it shines in more scenarios.
Behaviors
How is the memoized result invalidated?
Each element in the array is memoized individually and sequentially. The equality check includes:
- The element value
- The
callbackfn
The equality check is performed by the Object.is function. If an element is invalidated, all subsequent elements in the array will also be invalidated.
Given same instance of callbackfn:
[1, 2, 3]followed by[1, 2, 3, 4]will call reducer 4 times with:1, 2, 3, 4[1, 2, 3]followed by[1, 2, 4]will call reducer 4 times with:1, 2, 3, 4[1, 2, 3]followed by[1, 2, 2.5, 3]will call reducer 5 times with:1, 2, 3, 2.5, 3[1, 2, 3]followed by[1, 2]will call reducer 3 times with:1, 2, 3[1, 2, 3]followed by[], then followed by[1, 2, 3]will call reducer 6 times with:1, 2, 3, 1, 2, 3[1, 2, 3]followed by[0, 1, 2, 3]will call reducer 7 times with:1, 2, 3, 0, 1, 2, 3
Contributions
Like us? Star us.
Want to make it better? File us an issue.
Don't like something you see? Submit a pull request.