Skip to content

Instantly share code, notes, and snippets.

@johnrom
Last active March 12, 2021 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnrom/4e8bc65110c689006663c7736539e892 to your computer and use it in GitHub Desktop.
Save johnrom/4e8bc65110c689006663c7736539e892 to your computer and use it in GitHub Desktop.
An hook that lets you cache the value of a selector to return previous version and bail out of useState updates.
/**
* Used in https://github.com/formium/formik/pull/3089/files
* Based on https://github.com/dai-shi/use-context-selector/issues/19#issuecomment-767198162
* Gist: https://gist.github.com/johnrom/4e8bc65110c689006663c7736539e892
*/
import { useMemo } from 'react';
export type Selector<Value, Return> = (value: Value) => Return;
export type Comparer<Return> = (prev: Return, next: Return) => boolean;
const UNINITIALIZED_VALUE = Symbol();
/**
* A hook that caches the value of a selector given an optional comparer.
*
* It will return the previous value when present and comparer returns true,
* bailing out of setState and consequent renders.
*
* Useful for optimizing selectors for useContextSelector, useSubscriptions, useMutableSource, etc.
* @param selector A memoized or constant selector
* @param comparer A memoized or constant comparer
*/
export const useOptimizedSelector = <Value, Return>(
selector: Selector<Value, Return>,
comparer: Comparer<Return> = Object.is
): Selector<Value, Return> => {
return useMemo(() => {
let cachedValue: Return | typeof UNINITIALIZED_VALUE = UNINITIALIZED_VALUE;
return (value: Value) => {
const newValue = selector(value);
if (
cachedValue === UNINITIALIZED_VALUE ||
!comparer(cachedValue, newValue)
) {
cachedValue = newValue;
}
return cachedValue;
};
}, [selector, comparer]);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment