[Next.js][ํ”„๋กœ์ ํŠธ] ๐Ÿ’šColor Inside (5) - ๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ ๊ตฌํ˜„

์šฐ์—ฅยท2024๋…„ 8์›” 20์ผ

LoadingSpinner ์ปดํฌ๋„ŒํŠธ

'use client';

import useTypingWords from '@/hooks/useTypingWords';
import { useEffect } from 'react';
import Character from './assets/Character';
import Spinner from './assets/Spinner';

const LoadingSpinner = () => {
  useEffect(() => {
    document.body.style.overflow = 'hidden';
    return () => {
      document.body.style.overflow = 'auto';
    };
  }, []);

  const loadingText = '๋‹น์‹ ์˜ ๊ฐ์ •์„ ์œ„ํ•œ ๊ณต๊ฐ„์„ ์ค€๋น„์ค‘์ด์—์š”! ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”.';
  const typingText = useTypingWords(loadingText);

  return (
    <div className="fixed top-0 bottom-0 left-0 right-0 z-20 flex flex-col items-center justify-center bg-layout gap-16px-col-m md:gap-16px-col">
      <div className="flex items-center justify-center">
        <div className="relative md:inline-flex hidden">
          <span className="loader">
            <Spinner />
          </span>
        </div>
        <div className="relative md:hidden inline-flex">
          <span className="loader-mobile">
            <Spinner />
          </span>
        </div>
        <Character />
      </div>
      <div className="flex items-center">
        <p className="relative text-layout text-start text-14px-m md:text-20px font-normal tracking-0.28px md:tracking-tight">
          {loadingText}
        </p>
        <p className="absolute text-start text-14px-m md:text-20px font-normal tracking-0.28px md:tracking-tight">
          {typingText}
        </p>
      </div>
    </div>
  );
};

export default LoadingSpinner;

ย 

useTypingWords hook ๊ตฌํ˜„

  • ๋กœ๋”ฉ ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์ผ ๋•Œ ๋กœ๋”ฉ ๋ฉ”์„ธ์ง€๊ฐ€ ํ•œ ๊ธ€์ž์”ฉ ๋‚˜ํƒ€๋‚˜๋„๋ก ํ•˜๋Š” hook ๊ตฌํ˜„
'use client';

import { useEffect, useState } from 'react';

const useTypingWords = (text: string): string => {
  const [typing, setTyping] = useState<string>('');
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    const typingWords = setInterval(() => {
      if (typing.length === text.length) return;

      setTyping((prevTyping) => {
        const nextTyping = prevTyping ? prevTyping + text[count] : text[0];
        setCount(count + 1);

        return nextTyping;
      });
    }, 100);

    return () => clearInterval(typingWords);
  }, [count, text]);

  return typing;
};

export default useTypingWords;
profile
๐ŸŒธ๐Ÿ˜Š๐ŸŒธ

0๊ฐœ์˜ ๋Œ“๊ธ€