Skip to content

The useLayoutEffect hook

Suppose you have a parent component A and a child B, and you want to run a useEffect hook on mount in the parent first, followed by another useEffect hook in the child.

For example, you have a child component which overrides the default styles of the parent on mount.

This was a problem I faced.

You might try this, but it does not work as expected:

const A = () => {
    useEffect(() => console.log("Parent useEffect"), []);
    console.log("Parent body");

    return <B />;
};

// omitted

const B = () => {
    useEffect(() => console.log("Child useEffect"), []);
    console.log("Child body");
};

/*Logs
 * Parent body
 * Child body
 * Child useEffect
 * Parent useEffect*/

The child component's useEffect is being called before the parent component. Why is this happening?

useEffect runs after every completed render. If no dependencies are specified in the dependency array (the second argument), it will run after the first render.

In the above example, the parent A begins rendering first, followed by the child B. The child finishes rendering before the parent, and so its useEffect hook is called first, followed by the parent's.

Is there a way to run effects in the parent, before the child?

useLayoutEffect

You can use useLayoutEffect.

useLayoutEffect runs synchronously, before the browser has had a chance to paint.

We can rewrite our example above to the following:

const A = () => {
    useLayoutEffect(() => console.log("Parent useEffect"), []);
    console.log("Parent body");

    return <B />;
};

// omitted

const B = () => {
    useEffect(() => console.log("Child useEffect"), []);
    console.log("Child body");
};

/*Logs
 * Parent body
 * Child body
 * Parent useEffect
 * Child useEffect*/

Now, effects in the child run before the parent!

A caveat: useLayoutEffect is synchronous and will block visual updates, so avoid doing heavy lifting here.

The next time you need to run an effect in the parent before the child, consider using useLayoutEffect.

Comments