UNPKG

react-stable-ref

Version:

An assortment of utilities for testing against unstable references in React

168 lines (105 loc) 5.02 kB
<p align="center"> <img width="300" src="./assets/logo.png" alt="Test stable references"> </p> # react-stable-ref 🤷‍♂️ [![min](https://img.shields.io/bundlephobia/min/react-stable-ref.svg)](https://www.npmjs.com/package/react-stable-ref) [![npm](https://img.shields.io/npm/v/react-stable-ref.svg)](https://www.npmjs.com/package/react-stable-ref) [![Downloads per month](https://img.shields.io/npm/dm/react-stable-ref.svg)](https://www.npmjs.com/package/react-stable-ref) Your stable reference utility library with everything you need to test, visualize and protect against the dreaded unintentional rerender 😱 [Try it here](https://danieldelcore.github.io/react-stable-ref/) ## Get started 🏗 **Installation** `npm install --save react-stable-ref` or `yarn add react-stable-ref` ## Example ```jsx 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](https://www.npmjs.com/package/eslint-plugin-react-hooks) 🥰. 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:** ```jsx 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](https://usehooks.com/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:** ```jsx 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:** ```jsx const RenderCounter = () => { const count = useRenderCount(); return <button>{count}</button>; }; ``` ### `<RenderCount />` A visual component that keeps track of the number of renders that have occurred. <p align="left"> <img width="200" src="./assets/rendercount.png" alt="Render count component"> </p> **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](https://twitter.com/pablostanley) and contributors of [Open Peeps](https://www.openpeeps.com/?ref=react-stable-ref) for the logo. ## Resources - [Introducing Hooks](https://reactjs.org/docs/hooks-intro.html) - [Making Sense of React Hooks](https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889) - [When to useMemo and useCallback](https://kentcdodds.com/blog/usememo-and-usecallback/)