thumbnail

제너레이터와 이터레이터 React에서 활용하는 타이핑 애니메이션

생성일2024. 10. 30.
태그
작성자지한솔

notion image

제너레이터와 이터레이터란?

JavaScript에서 제너레이터(Generator)이터레이터(Iterator)는 반복 가능한 작업을 효율적으로 처리하기 위한 도구입니다. 특히, 제너레이터는 값을 필요할 때마다 생성하며 작업 흐름을 제어할 수 있는 독특한 방식으로 작동합니다.
제너레이터를 활용하면 복잡한 상태 관리를 자동화하거나, 비동기 로직과 반복적인 작업을 결합하여 직관적이고 간결한 코드를 작성할 수 있습니다. 이번 글에서는 제너레이터와 이터레이터의 기본 개념을 정리하고, 실무 예제로 타이핑 애니메이션 컴포넌트를 구현하는 과정을 통해 활용 방법을 알아보겠습니다.

제너레이터 (Generator)

제너레이터function*으로 정의하며, 실행을 중단하거나 재개할 수 있습니다. 내부에서 yield 키워드를 사용해 값을 반환하고 실행을 멈추는 지점을 지정합니다.

문법과 사용법

function* generatorFunction() { yield 1; // 첫 번째 값 yield 2; // 두 번째 값 yield 3; // 세 번째 값 }
이제 generatorFunction을 호출하면, 이터레이터 객체가 반환됩니다.
const gen = generatorFunction(); console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: 3, done: false } console.log(gen.next()); // { value: undefined, done: true }
  • value: yield로 반환된 값
  • done: 제너레이터가 끝났는지 여부
제너레이터는 필요한 순간에 값을 생성하는 "게으른 평가(Lazy Evaluation)" 방식으로 작동합니다. 따라서 반복 작업이나 대규모 데이터 처리에서 효율적입니다.

이터레이터 (Iterator)

이터레이터next() 메서드로 순차적인 값을 반환하는 객체입니다. 제너레이터는 이터레이터를 생성하기 위한 간편한 도구입니다.

직접 구현한 이터레이터

const iterator = { current: 0, max: 5, next() { if (this.current < this.max) { return { value: this.current++, done: false }; } return { value: undefined, done: true }; }, };
이터레이터는 상태를 직접 관리해야 하며, 위 코드에서 currentmax가 상태 관리의 핵심입니다.

제너레이터 기반 타이핑 애니메이션

React에서 제너레이터를 사용하여 타이핑 애니메이션을 구현할 수 있습니다. 아래는 제너레이터를 활용한 TextAnimator 컴포넌트입니다.

제너레이터 활용

import React, { useState, useEffect } from 'react'; interface TextAnimatorProps { ms: number; wait: number; text: string; } const TextAnimator: React.FC<TextAnimatorProps> = ({ ms, wait, text }) => { const [displayText, setDisplayText] = useState(''); useEffect(() => { const run = function* () { while (true) { for (let i = 1; i <= text.length; i++) { yield text.slice(0, i); } yield new Promise((resolve) => setTimeout(resolve, wait)); for (let i = text.length - 1; i >= 0; i--) { yield text.slice(0, i); } yield new Promise((resolve) => setTimeout(resolve, wait)); } }; const iterator = run(); const handleIteration = async () => { for (const value of iterator) { if (value instanceof Promise) { await value; } else { setDisplayText(value as string); await new Promise((resolve) => setTimeout(resolve, ms)); } } }; handleIteration(); return () => iterator.return?.(); }, [text, ms, wait]); return <div>{displayText}</div>; }; export default TextAnimator;

제너레이터 없이 for문으로 구현

setIntervalfor문으로 비슷한 결과를 구현할 수 있습니다. 그러나 아래 코드에서는 제너레이터 없이 상태 관리가 복잡해지는 것을 확인할 수 있습니다.
const TextAnimatorWithoutGenerator: React.FC<TextAnimatorProps> = ({ ms, wait, text }) => { const [displayText, setDisplayText] = useState(''); let interval: NodeJS.Timeout | null = null; useEffect(() => { let i = 0; let direction = 1; interval = setInterval(() => { setDisplayText(text.slice(0, i)); i += direction; if (i === text.length || i === 0) { direction *= -1; } }, ms); return () => { if (interval) clearInterval(interval); }; }, [text, ms]); return <div>{displayText}</div>; };

제너레이터의 장점

  1. 코드 가독성:
      • yield를 사용하면 반복 작업의 의도가 명확합니다.
      • 상태 관리나 흐름 제어 코드가 줄어듭니다.
  1. 비동기 작업 통합:
      • yieldPromise를 조합하여 자연스럽게 비동기 작업을 처리할 수 있습니다.
  1. 메모리 효율성:
      • 필요한 값만 생성하므로 메모리 낭비가 없습니다.

타이핑 애니메이션

이번 글에서 소개한 제너레이터 기반 타이핑 애니메이션 컴포넌트는 아래 링크에서 확인할 수 있습니다. 또한, 해당 컴포넌트를 라이브러리 형태로 제작하여 더 간단하게 사용할 수 있도록 제공했습니다.

코드 확인

GitHub Repository: hansolbangul/typing-animated
위 링크에서 모든 소스 코드와 구현 방식을 확인할 수 있습니다.

설치 방법

npm을 통해 쉽게 설치할 수도 있습니다. 아래 라이브러리를 설치하여 컴포넌트를 바로 사용해보세요.
npm install @hansolbangul/animated-typo

라이브러리 사용 예시

import React from 'react'; import { AnimatedTypo } from '@hansolbangul/animated-typo'; const App = () => { return ( <div> <AnimatedTypo text="Hello, World!" ms={100} wait={1000} /> </div> ); }; export default App;
이제 직접 코드를 확인하고, 라이브러리를 통해 프로젝트에 쉽게 적용해보세요! (피드백은 언제나 환영입니다!)