0

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

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • It's because React's "Strict Mode" runs your useEffect twice in development, which results in a miscalculation transform style within [screen1 style](https://i.imgur.com/lnza1rR.png) -- it's being set as ~300px, when it should be 0px. You can either ignore it as this will only happen in development OR you can use an `isMounted` ref to prevent the useEffect from running twice: [working example](https://codesandbox.io/s/inspiring-nova-pj52qf). – Matt Carlotta Jul 03 '23 at 04:35
  • @MattCarlotta Why using the legacy API `ReactDOM.render` with 'strict mode` works well? useEffect not run twice in this API? – Trouble Lee Jul 03 '23 at 07:28

2 Answers2

1

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

Lin Du
  • 88,126
  • 95
  • 281
  • 483
0

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();
    }, [])
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 05 '23 at 11:33