skip to Main Content

Does the useEffect hook run in the same browser render cycle, in React 18, after the component has been rendered or it is possible that the hook will be delayed and run later? In other words, does React guarantee that render and the corresponding useEffect hook are executed atomically?

My specific case, although I do not think it matters: my component renders an editor and I need to focus the editor once it is rendered if the client code specified the autofocus option. I imagine that if useEffect is run in a subsequent browser render cycle, it is possible to set focus to another component after the editor has been rendered but before useEffect is executed, which would effectively steal the focus from that other component.

2

Answers


  1. As per the docs, React useEffect Hook is executed after the Component render.

    But it is not executed immediately after, if that is what you mean by "atomically". In particular, React renders first all the child Components, and also executes their own useEffect Hooks first, from descendants to ancestors (see What is the correct order of execution of useEffect in React parent and child components?)


    it is possible to set focus to another component after the editor has been rendered but before useEffect is executed, which would effectively steal the focus from that other component.

    Indeed, since only 1 Element can have browser focus, the last executed .focus() expression wins.

    As described above, all child Components will have their useEffect Hook executed first, hence they may already try to apply focus. Hence you may be stealing focus from one of your children, which may not be problematic depending on your exact use case.

    Similarly, another Component may steal the focus of your Editor, e.g. if it is a next sibling or parent Component.

    BTW, here "steal" does not mean that focus will visually jump from one Element to another: all useEffect Hooks will be executed (in above described order) before next React render attempt:

    it’s guaranteed to fire before any new renders. React will always flush a previous render’s effects before starting a new update.

    So only the last executed .focus() will effectively visually appear to the visitor.

    Login or Signup to reply.
  2. Does the useEffect hook run in the same browser render cycle, in React 18, after the component has been rendered or it is possible that the hook will be delayed and run later?

    There will be things that happen in between, such as updating the dom and the browser painting. However, it is not possible that it will be delayed until after another render. If you’re using concurrent features such as startTransition then it is possible that the current render will be aborted, but in that case the effect will not run at all.

    In short: if your effect code runs, you can be guaranteed that it was created by the most recent render and is being run after that render.


    P.S, i did a test to see if i could force a render to happen synchronously, before some effects have run, using flushSync. Turns out react does not allow using flushSync during a lifecycle hook, so this can not break what i described above.

    Sandbox

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search