useEffect

The useEffect hook serves a the primary way for handling side effects in a Melody component.

It allows you to execute code when,

  • it is mounted

  • it is updated

  • it is unmounted (removed)

Execute a side effect when needed

useEffect(sideEffectFunction, cacheKeyProperties[])

The most common form of useEffect accepts a function, the side effect you want to execute, and an array of variables it depends on. Those cacheKeyProperties are used to determine whether to execute the side effect again or not.

// we'll create a reusable data loading hook for items
function useItemData({ itemId }) {
    // use an atom to store the data
    const [getData, setData, data] = useAtom({});
    // this hook will be executed after the component has been mounted
    // and it will only be executed again if the itemId changes
    useEffect(() => {
        // ceremony to get a URL and setup an abortable fetch
        const url = getItemDataUrl(itemId);
        
        const controller = new AbortController();
        const signal = controller.signal;
        
        fetch(url, { signal }).then(response => {
          return response.json();
          // finally update the data
        }).then(setData);
        // this function is executed when
        // 1. the component is unmounted or
        // 2. the itemId changes
        // we'll use it to cancel the request if its still running
        return () => controller.abort();
    }, [itemId]);
    return [ getData, data ];
}

The above example is trying to be realistic by also showing how you'd need to abort a request that is no longer useful. For that, it relies on the abortable fetch API which is not yet as widely spread as the original fetch API. You might need an additional polyfill to make it work.

However, the concept itself also lends itself very nicely towards usage with Rx.js which comes with an abortable ajax utility.

Execute a side effect on mount and unmount

useEffect(sideEffectFunction, [])

When given an empty array the side effect will never be evaluated again, as the cache key never changes. This gives a chance to build a side effect that executes when the component mounts and unmounts.

function useDocumentTitle(title) {
    useEffect(() => {
        // executed after component was mounted
        const oldTitle = document.title;
        document.title = title;
        // executed when the component is unmounted
        return () => document.title = oldTitle;
    }, []);
};

The above example is actually not a good one since you'd really want to re-evaluate the side effect when the title changes.

Use a side effect on mount, every render and unmount

useEffect(sideEffectFunction)

You can also omit the cacheKeyProperties array entirely if you want to create a side effect that executed every time the component is rendered.

function useSlowDeviceKiller() {
    useEffect(() => {
        // executed on component mount and every single render
        fibonacci(10);
        // this function will be executed on _every render_ before
        // the side effect is re-evaluated
        return () => fibonacci(7);
    });
}

Last updated

Was this helpful?