TECH

λ¦¬μ•‘νŠΈμ—μ„œ requestAnimationFrame μ‚¬μš© μ‹œ μ£Όμ˜ν•  점

ttaerrim 2024. 3. 17. 20:41

λ¦¬μ•‘νŠΈμ—μ„œ requestAnimationFrame APIλ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ κ²ͺμ—ˆλ˜ 문제λ₯Ό κ³΅μœ ν•΄ 보렀고 ν•©λ‹ˆλ‹€.

 

πŸ“Œ λ¬Έμ œκ°€ λ˜μ—ˆλ˜ μ½”λ“œ

function AnimationSection() {
    const [count, setCount] = useState(0);

    const text = 'welcome to ttaerrim world'.toUpperCase();
    const textRef = useRef<HTMLDivElement>(null);

    const animate = () => {  
      const width = textRef.current?.scrollWidth;  
      if (width) {  
        if (count > width) {  
          setCount(0);  
        } else {  
          setCount((c) => c + 10);  
        }  
      }  

      requestRef.current = requestAnimationFrame(animate);  
    };  
 
    useEffect(() => {  
      requestRef.current = requestAnimationFrame(animate);  
      return () => cancelAnimationFrame(requestRef.current);  
    }, []);
    
    // ... μƒλž΅
}

 

 

μœ νŠœλΈŒμ—μ„œ λ³Έ λ§›μžˆλŠ” μ½”λ”©λ‹˜μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈλ‘œ 5λΆ„λ§Œμ— ν…μŠ€νŠΈ 슀크둀 μ• λ‹ˆλ©”μ΄μ…˜ 효과(text marquee effect) λ§ˆμŠ€ν„°ν•˜κΈ°λ₯Ό 보고 μžλ°”μŠ€ν¬λ¦½νŠΈ 예제λ₯Ό λ¦¬μ•‘νŠΈ μ½”λ“œλ‘œ μž‘μ„±ν•˜μ—¬ μ• λ‹ˆλ©”μ΄μ…˜μ„ λ™μž‘ν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

 

 

 

 

μ˜μƒμ—μ„œ μ„€λͺ…ν•˜λŠ” λ°©μ‹λŒ€λ‘œ element의 widthκ°€ countλ₯Ό μ΄ˆκ³Όν•˜κ²Œ 되면 countλ₯Ό 0으둜 λ³€κ²½ν•˜μ—¬ λŠμž„μ—†μ΄ 흐λ₯΄λŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λŠ” μ• λ‹ˆλ©”μ΄μ…˜μ„ λ§Œλ“œλŠ” 것이 λͺ©ν‘œμ˜€μœΌλ‚˜ μ˜ˆμƒλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

 

 

 

 

μ΄μœ λŠ” useEffect λ‚΄μ—μ„œλŠ” μ‚¬μš©ν•˜λŠ” count λ³€μˆ˜κ°€ setCount둜 λ³€κ²½ν•˜λ”λΌλ„ μ΄ˆκΈ°κ°’ 0μ—μ„œ λ³€κ²½λ˜μ§€ μ•ŠλŠ” ν˜„μƒμ΄ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

κ·Έλ ‡κΈ° λ•Œλ¬Έμ— if문의 (count > width) μ‘°κ±΄μ ˆμ„ νƒˆ 수 μ—†μ—ˆλ˜ κ΅¬μ‘°μ˜€μŠ΅λ‹ˆλ‹€.

 

 

 

 

❓ useEffectκ°€ μ΄λ ‡κ²Œ λ™μž‘ν•˜λŠ” μ΄μœ λŠ” λ¬΄μ—‡μΌκΉŒμš”?

 

useEffect의 두 번째 인자둜 빈 배열을 μ „λ‹¬ν•˜λ©΄ useEffect둜 μ „λ‹¬ν•˜λŠ” μ½œλ°±ν•¨μˆ˜λ₯Ό ν•œ 번만 μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

그런데 μ΄λ ‡κ²Œ ν•˜λ©΄ μ• λ‹ˆλ©”μ΄μ…˜ 쀑에 μ˜¬λ°”λ₯Έ μƒνƒœλ₯Ό μœ μ§€ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

useEffect에 dependency둜 빈 배열을 μ „λ‹¬ν•˜λŠ” 것을 λ¦¬μ•‘νŠΈλŠ” μƒνƒœλ₯Ό μ΅œμ‹ μœΌλ‘œ μœ μ§€ν•  ν•„μš”κ°€ μ—†λ‹€λŠ” 의미둜 ν•΄μ„ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

λ”°λΌμ„œ 빈 배열을 dependecy둜 κ°€μ§€λŠ” useEffect λ‚΄μ—μ„œ state의 값을 κ°€μ Έμ˜€λ©΄ 항상 μ΄ˆκΈ°κ°’μ—λ§Œ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

 

 

 

 

λ”°λΌμ„œ λ‹€μŒκ³Ό 같이 μ• λ‹ˆλ©”μ΄μ…˜ μ½”λ“œλ₯Ό μˆ˜μ •ν–ˆμŠ΅λ‹ˆλ‹€.

 

function AnimationSection() {
  const [count, setCount] = useState(0);

  const text = 'welcome to ttaerrim world'.toUpperCase();
  const textRef = useRef<HTMLDivElement>(null);
  const requestRef = useRef<number>(0);
  const previousTimeRef = useRef<number>(0);

  const animate = (time: DOMHighResTimeStamp) => {
    const width = textRef.current?.scrollWidth;
    if (previousTimeRef.current !== undefined && width) {
      const deltaTime = Math.floor(time - previousTimeRef.current);
       setCount((prevCount) => (prevCount + deltaTime * 0.2) % width);
     }

     previousTimeRef.current = time;
     requestRef.current = requestAnimationFrame(animate);
  };

  useEffect(() => {
    requestRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(requestRef.current);
  }, []);

  // μƒλž΅
}

 

 

useEffect λ‚΄μ—μ„œλŠ” state의 μ΄ˆκΈ°κ°’μ„ κ°€μ Έμ˜€κΈ° λ•Œλ¬Έμ— setCount ν•¨μˆ˜λ„ setCount((count + deltaTime * 0.2) % width)처럼 μ‚¬μš©ν•˜λ©΄ 늘 λ˜‘κ°™μ€ 값을 count둜 μ§€μ •ν•˜λŠ” 것과 κ°™μŠ΅λ‹ˆλ‹€.

μ΅œμ‹ μ˜ μƒνƒœ 값을 μ‚¬μš©ν•˜λ €λ©΄ setState둜 ν•¨μˆ˜λ₯Ό λ„˜κ²¨ μ€λ‹ˆλ‹€.

 

 

 

setState(prevState ⇒ prevState + value)

이런 μ‹μœΌλ‘œ, ν˜„μž¬ μƒνƒœλ₯Ό κΈ°μ€€μœΌλ‘œ 값을 μ „λ‹¬ν•˜μ—¬ μ μš©ν•˜λ©΄ μƒνƒœ 값이 λ³€κ²½λ©λ‹ˆλ‹€.

 

 

 

μ• λ‹ˆλ©”μ΄μ…˜ λ™μž‘μ— μ‚¬μš©λ˜λŠ” μƒνƒœ κ°’ 쀑 값이 λ³€κ²½λ˜λ”λΌλ„ λ Œλ”λ§μ‹œν‚€μ§€ μ•Šκ³  싢을 λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 κ²½μš°μ—λŠ” useRefλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. useRefλŠ” λ³€κ²½λ˜λ”λΌλ„ λ Œλ”λ§μ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ• λ‹ˆλ©”μ΄μ…˜μ„ cleanup ν•  λ•Œ 계속 λ³€κ²½λ˜λŠ” reqeustAnimationFrame의 idλ₯Ό μ €μž₯ν•΄ 두어야 ν•˜κ³ , 경과된 μ‹œκ°„μ„ κΈ°μ€€μœΌλ‘œ μ• λ‹ˆλ©”μ΄μ…˜μ„ μ μš©ν•˜λŠ” 경우 νƒ€μž„μŠ€νƒ¬ν”„λ₯Ό κΈ°μ–΅ν•΄μ•Ό ν•©λ‹ˆλ‹€. 이 두 λ³€μˆ˜λ₯Ό useRefλ₯Ό μ‚¬μš©ν•΄ requestRef와 previousTimeRef에 μ €μž₯ν•΄ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

 

 

 

 

 

 

πŸ“Œ μ°Έκ³ 

Using requestAnimationFrame with React Hooks | CSS-Tricks - CSS-Tricks