Last active
May 20, 2021 12:43
-
-
Save tvler/eeff76e58d2f1d3ce8320ba96cfd2efe to your computer and use it in GitHub Desktop.
A custom React.memo memoization function that throws an error (in dev) if props change between renders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A strict React.memo memoization function, built off | |
* the one that comes built-in, that throws an error | |
* (in dev) if props change between renders. Props you | |
* want to allow can be passed in as arguments. | |
* | |
* This "don't allow by default" model makes it so | |
* further changes to a component don't silently | |
* undo any memoization optimizations done before. | |
* | |
* The underlying shallow equality function is the | |
* exact same function as the one react normally runs | |
* for React.PureComponent or React.memo components. | |
* (https://github.com/facebook/react/blob/fc33f12bdee1d0ffbcc83d25199cdf4d47252736/packages/shared/shallowEqual.js) | |
* | |
* Ex: | |
* const Component = (props) => { | |
* return <>Hello {props.name}</>; | |
* }; | |
* | |
* const MemoizedComponent = memo( | |
* Component, | |
* shallowEqualWarnInDev( | |
* 'name', // Allow `name` to change | |
* ), | |
* ); | |
*/ | |
export function shallowEqualWarnInDev<T>(...propsAllowedToChangeArr: Array<keyof T>) { | |
const propsAllowedToChange = new Set(propsAllowedToChangeArr); | |
return (prevProps: T, nextProps: T) => { | |
if (Object.is(prevProps, nextProps)) { | |
return true; | |
} | |
if ( | |
typeof prevProps !== 'object' || | |
prevProps === null || | |
typeof nextProps !== 'object' || | |
nextProps === null | |
) { | |
return false; | |
} | |
const keysA = Object.keys(prevProps) as Array<keyof T>; | |
const keysB = Object.keys(nextProps) as Array<keyof T>; | |
if (keysA.length !== keysB.length) { | |
return false; | |
} | |
// Test for A's keys different from B. | |
for (let i = 0; i < keysA.length; i++) { | |
if ( | |
!Object.prototype.hasOwnProperty.call(nextProps, keysA[i]) || | |
!Object.is(prevProps[keysA[i]], nextProps[keysA[i]]) | |
) { | |
if (__DEV__ && !propsAllowedToChange.has(keysA[i])) { | |
throw new Error(`The prop \`${keysA[i]}\` is not expected to change between renders.`); | |
} | |
return false; | |
} | |
} | |
return true; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment