React.StrictMode and createRoot influence my UI render

124 Views Asked by At

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

2

There are 2 best solutions below

1
On BEST ANSWER

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

1
On

Should use ScrollTrigger in this way

    const main = useRef(null);
    const tl = useRef()

    useLayoutEffect(() => {
        let ctx = gsap.context(() => {
            tl.current = gsap.timeline({
                scrollTrigger: {
                    trigger: '.screen1',
                    start: 'top top',
                    end: '+=200',
                    scrub: true,
                    pin: true,
                    markers: true,
                }
            })
                .fromTo(
                    '#img1',
                    {
                        opacity: 0,
                        x: 0
                    },
                    {
                        opacity: 1,
                        x: '20%',
                    })
                .fromTo(
                    '#img2',
                    {
                        opacity: 0,
                        x: '100%' 
                    },
                    {
                        opacity: 1,
                        x: '80%',

                    })
        }, main);
        return () => ctx.revert();
    }, [])