//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
를 사용했는데 내 코드에는 변수만 바꾸면 되는것이라 그냥 이대로 사용하려고 한다.