usePerishable()

A React hook for creating perishable elements for animation purposes.

Some animations require elements to be created and destroyed after a certain amount of time. For example - confetti particles, fireworks, or toast notifications.

These elements are perishable since they have a predefined lifespan after which they perish. Their only purpose is to be animated and then removed from the DOM.

This hook allows you to create perishable elements that will be removed after a certain amount of time, and optionally associate data to them.

Implementation

The basic idea is to create an array of unique IDs (and, optionally, some associated data) that you can iterate over to create any element you want.

Based on a given delay, the array will be updated and elements whose lifespan has expired will be removed. Finally, we can use the useEffect() hook to cleanup any pending timeouts when the component unmounts.

js
const usePerishable = () => {
    const [items, setItems] = useState([]);
    const timeouts = useRef({});

    useEffect(() => {
        // Cleanup pending timeouts when the component unmounts
        return () => Object.values(timeouts.current).forEach(clearTimeout);
    }, []);

    return {items, add: (delay, data) => {
        // Generate a unique ID
        const id = nanoid();
        // Create a new item with the given id & data
        setItems(arr => [...arr, { id, data }]);
        // Create a timeout to remove the item after the given delay
        timeouts.current[id] = setTimeout(() => {
            setItems(ids => ids.filter(item => item.id !== id));
            delete timeouts.current[id];
        }, delay);
    }};
};

Usage

You call add(delay, data) to create an item, and iterate over items to render the elements:

jsx
const Component = () => {
    const { items, add } = usePerishable();
    return (
        <>
            <button onClick={() => add(1000, 'some data')}>Create Perishable Item</button>
            {items.map(({ id, data }) => (
                <div key={id}>{data}</div>
            ))}
        </>
    )
}

Examples

Here's a simple confetti button that creates a new confetti particle every time it's clicked.

Clicking on the button calls the add() function PARTICLE_COUNT times with some random values. These values are then converted to CSS custom properties using objectToCustomProps() and are used to animated the elements.

Code Playground

Or how about this <ShineyButton/> that just draws your attention to it?

Code Playground

You can also make cool (and useless) stuff like this smokin' cursor trail

Code Playground

I've also used this hook to create the like button for this site. I'm using it for creating the heart-shaped "waves" and the number bubbles. You can see the code in this CodePen:

See the Pen 3D Heart Button by Yoav Kadosh (@ykadosh) on CodePen.
Don't keep this brilliance to yourself.

A newsletter for front-end web developers

Stay up-to-date with my latest articles, experiments, tools, and much more!

Issued monthly (or so). No spam. Unsubscribe any time.