useFlasher React Hook

The useFlasher React Hook and a mistake that nobody sees

August 1, 2020
In category Development

When I was hitting my head on the wall trying to figure out ways and patterns on how to handle local and global state using React Hooks, I saw many engineers are using the useFlasher hook.

import { useRef, useEffect } from 'react';

export const useFlasher = () => {
  const ref = useRef<HTMLElement>(null);
  useEffect(() => {
    if (!ref.current) return;
    ref.current.setAttribute(
      'style',
      'box-shadow: 0 0 4px 1px orange; transition: box-shadow 400ms ease-out;',
    );
    setTimeout(() => {
      if (!ref.current) return;
      ref.current.setAttribute('style', '');
    }, 300);
  });
  return ref;
};

Its purpose it to flash an element when it renders so to see when a component re-renders on state changes. It applies to a component ref so to get the HTMLElement and it has an effect that sets a box-shadow style to that element and sets-up a timer timeout to clear the style after X milliseconds. Very clever and practical way to visually check for component re-renders when using hooks.

One minor mistake that this hook effect has is that it does not clear the timer timeout on burst calls. For example, if I set the useFlasher to a component that updates on user text input, the flash effect will execute per less than 50 milliseconds and we won’t have an accurate visual effect. Small thing but why not fix it…

import { useRef, useEffect } from 'react';

export const useFlasher = () => {
  const ref = useRef<HTMLElement>(null);
  useEffect(() => {
    if (!ref.current) return;
    ref.current.setAttribute(
      'style',
      'box-shadow: 0 0 4px 1px orange; transition: box-shadow 400ms ease-out;',
    );
    const timer = setTimeout(() => {
      if (!ref.current) return;
      ref.current.setAttribute("style", "");
    }, 300);
    return () => clearTimeout(timer);
  });
  return ref;
};
0 0

comments powered by Disqus