Project/portfolio

타이핑 애니메이션 이슈

Hyunsoo_Kim 2024. 5. 5. 17:42

Trouble

 

import React, { useState, useEffect } from "react";
import styles from "./Index.module.css";

const Home = () => {
  const myName = "Hyunsoo_Kim"; //length: 11
  const [mainText, setMainText] = useState<string>("");

  useEffect(() => {
    let index = 0;
    const intervalId = setInterval(() => {
      if (myName.length > index) {
        setMainText((prevText: string) => prevText + myName[index]);
        index++;
        index === 10 && clearInterval(intervalId);
      }
    }, 90);

    return () => clearInterval(intervalId);
  }, []);

  return (
    <div className={styles["wrapper"]}>
      <div className={styles["content"]}>
        <div className={styles["mainText"]}>
          <h1 className={styles["mainText__text"]}>{mainText}</h1>
          <div className={styles["mainText__blink"]}></div>
        </div>
        <p className={styles["subText"]}>FE_developer</p>
      </div>
    </div>
  );
};

export default Home;
gif

 

1. 타이핑 애니메이션을 구현중 문자열 중간의 한 글자가 빠져서 출력되는 현상이 나타났다

2. setInterval의 콜백함수 안에서 console.log(mainText); 를 넣으니 빈문자열만 출력하고 있었다

3. 이를통해 useEffect 내부에서는 state값을 참조하지 못하고 있다는 것을 발견했다

4. useEffect 내부에서 state값을 참조하기위해 의존성배열에 state값을 넣으면 무한렌더링이 일어나기 때문에 올바른 솔루션이 아니다

 

Solution

 

import React, { useState, useEffect } from "react";
import styles from "./index.module.css";

const Home = () => {
  const myName = "Hyunsoo_Kim"; //length: 11
  const [mainText, setMainText] = useState<string>("");
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    if (count < 11) {
      const typingInterval = setInterval(() => {
        setMainText((prev: string) => {
          let result = prev ? prev + myName[count] : myName[0];
          setCount(count + 1);

          if (count === 10) {
            clearInterval(typingInterval);
          }

          return result;
        });
      }, 90);

      return () => {
        clearInterval(typingInterval);
      };
    }
  });

  return (
    <div className={styles["wrapper"]}>
      <div className={styles["content"]}>
        <div className={styles["mainText"]}>
          <h1 className={styles["mainText__text"]}>{mainText}</h1>
          <div className={styles["mainText__blink"]}></div>
        </div>
        <p className={styles["subText"]}>FE_developer</p>
      </div>
    </div>
  );
};

export default Home;