英文:
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 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][1]
Can anyone explain these differences?
---------Edit-----------
context is a solution, but it's broken again after adding another `<div id='img2'>` for animation
[1]: https://codesandbox.io/s/friendly-sunset-lfp4gs?file=/src/index.js:519-537
<details>
<summary>英文:</summary>
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][1]
Can anyone explain these differences?
---------Edit-----------
context is a solution, but it's broken again after add another `<div id='img2'>` for animation
[1]: https://codesandbox.io/s/friendly-sunset-lfp4gs?file=/src/index.js:519-537
</details>
# 答案1
**得分**: 1
从[`gsap.context()`](https://greensock.com/docs/v3/GSAP/gsap.context())文档中:
> `gsap.context()` 解决了 React 18 中 "Strict Mode 中 `useEffect()` 双重调用" 问题,通常会破坏 `from()` 逻辑 - 只需在 `useEffect()` 清理函数中对上下文调用 `revert()`:
```ts
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">加载图片</div>
</div>
<div className="screen2"></div>
<div className="screen3"></div>
<div className="screen4"></div>
</div>
);
}
export default App;
英文:
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;
答案2
得分: 0
使用ScrollTrigger的方式如下:
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();
}, [])
英文:
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();
}, [])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论