Skip to content

yairEO/react-bouncer

Repository files navigation

Wrap components with a debounce, throttle, or any other delayed-rendering method, to stop them from re-rendering often when their props change.


Motivation

React.memo can be used to control whether a certain (wrapped) component should be rendered or not, by providing it with custom method as the a second parameter, but memo is unhelpful in some situations.

Sometimes it is wished to limit the number of times a component is rendered, for example, to a specific FPS or just to debounce it, so if it is called often, with different props, it will only actually re-render once those often calls are ceased (for enough time).

Sometimes components are very "expensive" to to re-render, in terms of performance (intense CPU usage), or they do async operations such as network requests. Assuming the parent-component which is causing these re-renders (by updating props often) cannot be refactored, or the cause is a deep mystery (due to code complexity), then wrapping those often-rendered components with bouncer HOC should alleviate the symptoms.


Install:

Use from CDN / Download from this repo / NPM

npm i @yaireo/react-bouncer -S

Usage Examples:

import bouncer from '@yaireo/react-bouncer'
import throttle from 'lodash.throttle' // throttle example

// simplified example for a component which gets rendered often due to props change
const Foo = ({x,y}) => `${x} ${y}`

// uses 300ms `debounce` by default
const DebouncedFoo = bouncer(Foo)
DebouncedFoo.displayName = 'DebouncedFoo'

// use a `throttle` method instead of the default `debounce` (or use your own custom one)
const ThrottleddFoo = bouncer(Foo, 300, throttle)
ThrottleddFoo.displayName = 'ThrottleddFoo'

// use them in another component which might render them often with different props
const App = () => {
  const [pos, setPos] = useState({x:0, y:0})

  // re-render on mouse move
  useEffect(() => {
    const onMouseMove = e => setPos({x: e.pageX, y: e.pageY})
    window.addEventListener('mousemove', onMouseMove)
    return () => window.removeEventListener('mousemove', onMouseMove)
  }, [])

  return <>
      <DebouncedFoo {...pos}/>
      <ThrottleddFoo {...pos}/>
  </>
}