Skip to content

Issue: useEffect executed before browser can paint DOM update #20863

@limekiln

Description

@limekiln

To my understanding, useEffect should always run after the browser acutally did paint any updates. This way, I tried to ensure that a loading indicator is rendered after a user submits data but before a blocking function execution (e.g. a fetch operation where the data is waited on) is executed. The code looks somewhat like the following:

Wrapper component to which a loading indicator can be passed:

export const LoadingWrapper = ({ callback, children}) => {
  useEffect(() => {
      if (typeof callback === "function") callback();
  }, [])

  return <React.Fragment> {children} </React.Fragment>
}

Usage:

const [loading, setLoading] = useState(false);

const blockingFunction = () => {
    // some functionaliy which blocks painting updates
}

return (
    // some kind of input elements which change the `loading` state on submit
    
    { loading &&
        <LoadingWrapper callback={blockingFunction}>
            <div> Loading! </div>
        </LoadingWrapper>
)

I would expect from the documentation that the callback function is executed after the "Loading" div is rendered on the screen, but that is actually not the case. The new div appears after the blocking call is completely resolved.

To get it working, I acutally have to use a local state variable in addition to trigger the effect:

export const LoadingWrapper = ({ callback, children}) => {
    const [isMounted, setIsMounted] = useState(false)

    useEffect(() => {
        setIsMounted(true);
    }

    useEffect(() => {
        if (isMounted && typeof callback === "function") callback();
    }, [isMounted]

    return <React.Fragment> {children} </React.Fragment>
}

Using this, I also observed some strange browser dependent behaviour. If input changes (which lead loading being set to true) are submitted onBlur of the input, it works fine in Chrome as well as in Firefox. Submitting these changes onKeyPress (while checking if the pressed key was the Enter key), it works in Firefox, but not in Chrome.

Does anyone have an idea what exactly is going on here or do I miss something important?

UPDATE:
I added a code sandbox: https://codesandbox.io/s/effectrendering-umtwo

The behaviour is quite strange:
In Chrome, triggering onBlur works (almost) always, sometimes it seems to bug out. Triggering onKeyPress will never trigger the spinner, except when onBlur was triggered before with the exact same input string (even though this string should have no influence at all here).
In Firefox, neither onBlur nor onKeyPress will trigger the spinner for me.

Tested versions:
Chrome 88.0.4324.150 (64-Bit)
Firefox 85.0.2 (64-Bit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions