//HomeSection6
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import { useEffect, useRef, useState } from "react";
import { gsap } from "gsap/all";
const container = css`
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
color: white;
font-weight: 900;
font-size: 2rem;
background: linear-gradient(#f9fafb, black);
`;
function HomeSection6() {
const innerText = "절차는 간단해요";
const textArea = useRef();
const [text, setText] = useState("");
const [count, setCount] = useState(0);
console.log("mount");
const interval = () => {
setInterval(() => {
console.log(count);
if (count === innerText.length) {
clearInterval(interval);
console.log("claer");
return;
}
setText(text + innerText[count]);
setCount(count + 1);
}, 1000);
};
useEffect(() => {
if (!textArea) return;
gsap.to(".section6-text", {
duration: 2,
scrollTrigger: {
trigger: ".section6-text",
toggleActions: "restart none restart none",
onEnter: () => interval(),
start: "200 60%",
end: () => "+=500",
markers: true,
},
});
return () => clearInterval(interval);
});
return (
<div css={container} className="section6-text" ref={textArea}>
<p>{text}</p>
</div>
);
}
export default HomeSection6;
innerText를 변화시키는 함수를 실행한다.setInterval함수를 사용한다.gsap의 toggleAction 설정과 onEnter, onEnterBack을 사용해 해당 섹션에 들어올때마다 typing액션이 실행된다. text를 한글자씩 늘리며 카운트를 센 뒤 카운트가 문자의 길이와 같아지면 clearInterval로 setInterval을 없애준다.
clearInterval이 제대로 되지 않는 것 같다.clearInterval로 해결count의 값이 바뀌면서 재렌더링된다.
클로저(Closure)
외부함수가 종료되었는데 내부함수가 계속 실행되는것 (자세한 것은 다른 포스팅에서)
setTimeout은 webApi이며 비동기이다. 따라서 callback queue에 쌓이고 call Stack이 비면 호출된다.
렌더링 -> setText와 setCount를 callback queue에 등록 후 종료
이때의 count의 값은 렌더링 되면서 초기화된다.
따라서 무한루프 (초기화 됐지만 2이상의 값이 나오는 것은 렌더링 된 상태에서 이전에 등록된 값이 겹쳐서 호출되기 때문)
redux에 등록하기
리렌더링이 되더라도 값을 유지시키기
useRef() 사용
useRef는 dom을 선택하는 용도도 있지만 값을 저장하는 용도로도 쓰인다.
특히 값이 바뀌더라도 리렌더링되는 것을 방지해준다.
let interval = useRef(null);
useEffect(() => {
if (!textArea) return;
let intervalId;
interval.current = () => {
console.log(count);
intervalId = setInterval(() => {
if (count === innerText.length) {
clearInterval(intervalId);
return;
}
setText(text + innerText[count]);
setCount(count + 1);
}, 100);
};
gsap.to(".section6-text", {
duration: 2,
scrollTrigger: {
trigger: ".section6-text",
onEnter: () => interval.current(),
start: "200 60%",
end: () => "+=500",
markers: true,
},
});
return () => clearInterval(intervalId);
});
interval.current에 callback을 저장하는 것으로 해결
해결하고 나니 누군가가 만든 custom hook 이 있다고한다.
내부 코드를 살펴보니 useRef를 사용했는데 내 코드에는 변수만 바꾸면 되는것이라 그냥 이대로 사용하려고 한다.