via dev.to

via dev.to

기본 로직


타자기로 한 글자씩 입력하는 효과(Typewriter Effect)는 이미 수 많은 라이브러리가 있지만, setInterval 타이머 API를 이용해서 직접 구현할 수 있다. 원래 문장(텍스트)을 한 글자씩 자른 후 가장 앞에 글자부터 하나씩 이어 붙이는 방식이다.

<div>
	<span class="content"></span>
	<span class="blink" />
</div>
const $content = document.querySelector(".content");

function typewriter(target, sentence, speed = 200) {
	const split = sentence.split("");
  let text = "";
  let i = 0;
  
  const timer = setInterval(() => {
    if (i < split.length) {
      text += split[i++]; // ++는 후위 증감(증가하기전 값 반환)
      target.textContent = text;
    } else {
      clearInterval(timer);
    }
  }, speed);
};

typewriter($content, 'hello world', 400);

깜빡이는 커서 효과는 | 콘텐츠를 갖는 <span> 태그에, step-end step-start 같은 애니메이션을 추가한다. :after 수도 클래스를 사용하지 않고 <span>|</span> 형태로 입력해도 된다.

.blink::after {
	content: "|";
}

.blink {
	animation: blink 1s step-end infinite;
	font-weight: bold;
	margin-left: 1px;
}

@keyframes blink {
	50% {
		opacity: 0;
	}
}

React Hook으로 만들기


React에 적용할 때도 setInterval을 이용해 위와 비슷한 로직으로 작성하면 된다.

export default function useTypeWriter({ content, sec = 200, hasBlink = false }) {
  const [displayedContent, setDisplayedContent] = useState('');
  const [index, setIndex] = useState(0);

  useEffect(() => {
    const animKey = setInterval(() => {
      setIndex(index => {
        if (index < content.length - 1) {
          return index + 1;
        }
        clearInterval(animKey);
        return index;
      });
    }, sec);
    return () => clearInterval(animKey);
  }, []);

  useEffect(() => {
    setDisplayedContent(displayedContent => displayedContent + content[index]);
  }, [index]);

  return (
    <>
      {displayedContent}
      {hasBlink && <span className="blink" />}
    </>
  );
}

작성한 Hook은 아래처럼 원하는 조건(깜빡임 커서 여부, 입력 속도)에 맞춰 실행할 수 있다.

import useTypeWriter from '@/hooks/useTypeWriter';

export default function Component() {

	const typingText = useTypeWriter({
    content: 'Hello World',
		sec: 200,
    hasBlink: true,
  });

	return <p>{typewriterText}</p>;
}

제너레이터 함수로 구현하기