javascriptreactjsreact-hooksgsapreact-strictmode

React.StrictMode and createRoot influence my UI render


I am new to react. This is a generated code block in my project by create-react-app

const container = document.getElementById("root");
const root = createRoot(container);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Now I am using gsap to render anime. There is a disgusting blank block at the top of the page. Finally I found out the reason is these code, I also find out the solutions, but I do not know why.

1. ReactDOM.render with <React.StrictMode> success.
2. createRoot.render(<App />) success.
3. createRoot.render() with <React.StrictMode> FAILED.

Here is the project Can anyone explain these differences?

---------Edit-----------
context is a solution, but it's broken again after add another <div id='img2'> for animation


Solution

  • From the gsap.context() documentation:

    gsap.context() works around the React 18 "double-call of useEffect() in Strict Mode" issue that normally breaks from() logic - just call revert() on the Context in your useEffect() cleanup function:

    import { gsap } from 'gsap';
    import { ScrollTrigger } from 'gsap/ScrollTrigger';
    import React, { useEffect, useRef } from 'react';
    import './App.css';
    gsap.registerPlugin(ScrollTrigger);
    
    function App() {
        const ref = useRef(null);
    
        useEffect(() => {
            const ele = ref.current;
            let ctx = gsap.context(() => {
                gsap.fromTo(
                    ele.querySelector('#img1'),
                    {
                        opacity: 0,
                        x: -100,
                    },
                    {
                        opacity: 1,
                        x: 100,
                        scrollTrigger: {
                            trigger: ele.querySelector('.screen1'),
                            start: 'top top',
                            end: 'bottom center',
                            scrub: true,
                            pin: true,
                            markers: true,
                        },
                    },
                );
            });
            return () => ctx.revert();
        }, []);
    
        return (
            <div ref={ref}>
                <div className="screen1">
                    <div id="img1">load img</div>
                </div>
                <div className="screen2"></div>
                <div className="screen3"></div>
                <div className="screen4"></div>
            </div>
        );
    }
    
    export default App;
    

    codesandbox