Search code examples
domreactjslifecycle

reactjs is it possible to get a notification after the DOM is updated?


I have a component which renders a list of up to a thousand elements.

It takes 3/5 seconds to update the DOM, I mean after the component event componentDidUpdate, which is called after the changes have been flushed to the DOM, it takes 3/5 seconds to actually see the DOM updated.

I would like to show a spinning cog or something, but I don't know how, because I don't know how to get notified when the DOM updated is complete.

Anyone knows?


Solution

  • Javascript is single threaded, and all DOM operations are blocking. That means if the browser is busy adding to and updating the DOM, this will lock the Javascript thread until the DOM is updated. During the actual update, there's nothing you can do in code.

    This is assuming the UI lockup is actually from a raw, very large amount of DOM manipulation, and not some other underlying culprit. @zerkms's comment is also accurate that animated gifs, CSS animations, etc, generally do not run while the browser is locked up performing large calculations.

    If you anticipate browser lockup, the simplest solution is to show some spinner overlay, then run the command that updates your data. This way the spinner will already be in the DOM. When the update has completed, you can remove the spinner. It might look something like

    render() {
        return <div>
            <div onClick={ this.performLongRunningAction }>click me</div>
            { this.state.spinnerVisible ? 'Loading' : null }
        </div>
    }
    
    performLongRunningAction() {
    
        // First show the spinner...
        this.setState({ spinnerVisible: true }, () => {
    
            // Then after state has been set and spinner rendered, start the
            // long action
            executeLongRunningActionNow();
    
        });
    
    }
    
    // Then you need some mechanism to turn off the spinner state after the
    // task has completed
    componentWillReceiveProps( nextProps ) {
    
        // Did a task execute? Turn off the spinner before the next render
        if( nextProps.someCompletedFlag !== this.props.someCompletedFlag ) {
            this.setState({ spinnerVisible: false });
        }
    
    }
    

    Another solution is to break up the updating into chunks, so you update the DOM in intervals that are minimal enough not to lock up the Javascript thread. You have provided code, so fleshing out this solution is not possible.