react-stable-ref
v0.5.2
Published
An assortment of utilities for testing against unstable references in React
Downloads
255
Maintainers
Readme
react-stable-ref 🤷♂️
Your stable reference utility library with everything you need to test, visualize and protect against the dreaded unintentional rerender 😱
Get started 🏗
Installation
npm install --save react-stable-ref
or yarn add react-stable-ref
Example
const UnstableButton: FC<ButtonProps> = ({ onClick, children }) => {
// Unstable reference (unstableArray is reassigned on every render)
const unstableArray = ['1', '2', '3'];
const stableValue = 'Im stable because im a string';
useStableRefTester(); // Triggers re-renders every second
useWhichDepChanged({ unstableArray, stableValue });
/**
* Will output the following to the console (or onChange if you pass it in)
*
* > [useWhichDepChanged]: { unstableArray: { from: [1, 2, 3]; to: [1, 2, 3]}}
*/
return (
<button type="button" onClick={onClick}>
{children}
</button>
);
};
Motivation 🧠
It's not always obvious unstable references are passed into hooks such as useEffect
. This can cause unnecessary rerenders, which when left unchecked can decrease the performance of your app, cause jank and ultimately degrade your user's experience 😭.
Thankfully the React team have already thought about this and provided lint rules to help 🥰. But what if you're passing objects and arrays into dependency arrays which are not 'deeply' compared? How can you know for sure?
react-stable-ref
fills that gap and provides an assortment of utilities to help test, visualize and protect against the dreaded re-render 😱.
API 🤖
useStableRefTester()
A development only hook, which increments state over a predefined interval, triggering rerenders in your component.
Arguments:
- timeout:
Number
Timeout between rerenders
Returns:
count: Number
Example:
const UnstableButton = ({ children }) => {
const myArray = ['1', '2', '3'];
useStableRefTester();
useEffect(() => {
console.warn('I should not be called on every render');
}, [myArray]);
return <button>{children}</button>;
};
useWhichDepChanged()
A development only hook which emits (via console) which prop triggered an update. Useful when you are unsure which property changed in a useEffect
dependency array.
Inspired by: useWhyDidYouUpdate
Arguments:
- dependencies:
Object
A dependency object which mirrors the dependency array of the hook you are trying to test - onChange(changedDeps):
(changedDeps: Obj) => void
A callback which is fired when a dependency is changed.
Returns:
void
Example:
const UnstableButton = ({ children }) => {
const myArray = ['1', '2', '3'];
useWhichDepChanged({ myArray, children }, onChange(changedDeps) => {
console.log('UnstableButton: ', changedDeps); // UnstableButton: myArray
});
return <button>{children}</button>;
};
useRenderCount()
A hook which returns how many times it has been rendered.
Arguments:
- initialCount:
Number
Initial counter value
Returns:
- count:
Number
Current counter value
Example:
const RenderCounter = () => {
const count = useRenderCount();
return <button>{count}</button>;
};
<RenderCount />
A visual component that keeps track of the number of renders that have occurred.
Props:
- initialCount:
Number
Initial counter value - count:
Number
Provide a count for a controlled API
useDeeplyComparedEffect()
Coming soon...
A react hook for deeply comparing objects and arrays passed into its dependency array.
useCustomComparedEffect()
Coming soon...
A react hook to allow you to provide custom methods used to comparing dependencies and trigger an effect.
Thanks 😍
Huge thank you to Pablo Stanley and contributors of Open Peeps for the logo.