Next13 블로그 프로젝트

티스토리 Loading 컴포넌트 커스텀 훅을 이용하여 구현하는 방법

sakuraop 2023. 10. 11. 01:01

구현 목표는 티스토리 컴포넌트 로딩

 

결과 미리보기


구현 단계 요약

1. 데이터를 불러 오는 중이라면 "로딩"을 렌더링한다.

2. 데이터가 있다면 "있음"을 렌더링한다.

3. 데이터가 없다면 "없음"을 렌더링한다.

 

 


구현 방법

1. 로딩 화면을 보여주는 <Spin/> 컴포넌트를 만든다.

const Spin = () => {
  return (
    <div className={styles.loadingBox}>
      <Image src="/images/loadings/loading-s.gif" alt="loading" fill />
      <p>로딩중입니다.</p>
    </div>
  );
};

export default Spin;

티스토리처럼 로딩 빙글이가 돌아가고,
아래에는 로딩중이라는 메시지를 읽을 수 있도록 했다.

 

2. 로딩 상태를 조절할 useLoading 커스텀 훅을 만든다.

// useLoading.tsx

import React, { useState, useEffect } from "react";

const useLoading = () => {
  const [loading, setLoading] = useState<boolean>(true); // 로딩 여부

  useEffect(() => {
    // 3초 후에 loading을 false로 설정
    const timer = setTimeout(() => {
      setLoading(false);
    }, 3000);

    // 컴포넌트가 unmount 될 때 타이머를 정리
    return () => {
      clearTimeout(timer);
    };
  }, []);

  return { loading, setLoading };
};

export default useLoading;

loading 여부에 따라 <Spin/> 컴포넌트를 렌더링 한다.

 

setLoading으로 loading 여부를 조절한다.

 

useEffect를 이용해 3초 뒤에는 loading이 false로 바뀌도록 한다.

 

3. 데이터를 불러오는 훅을 만들고 useLoading을 가져온다.

const useLikes = () => {
  const [likes, setLikes] = useState([]); // 좋아요 한 게시물 리스트
  const { loading, setLoading } = useLoading();

  // 좋아요 한 게시물 리스트를 조회하여 state에 저장합니다.
  useEffect(() => {
    (async () => {
      try {
        // GET 요청을 보냅니다.
        const likes = await getManageLikesApi();
        // 게시물 리스트를 state에 저장합니다.
        setLikes(likes);
        setLoading(false);
      } catch (err) {
        console.error(err);
      }
    })();
  }, []);

  return { likes, setLikes, loading };
};

export default useLikes;

데이터 요청이 끝났다면 setLoading(false) 로 더이상 로딩을 하지 않도록 한다.

 

요청에 오류가 나서 setLoading이 실행되지 않더라도,

useLoading의 useEffect 훅이 3초가 지나면 setLoading(false) 를 실행하여 loading을 종료시킨다.

 

4. 조건별로 컴포넌트를 렌더링한다.

  return (
    <div className={styles.container}>
      {loading ? (
        <Spin />
        
      ) : likes.length ? (
        dates.map((date: string, index: number) => {
        // ...rendering items
      ) : (
      
        <NoItem
          h2={"아직 좋아요 한 게시물이 없습니다."}
          src={"/images/manageActivity/likes-activity-sample.png"}
        />
      )}
    </div>
  );
};

export default ManageLikes;

 

우선은 loading 컴포넌트가 나타나도록 합니다.

 

로딩중이면 loading 컴포넌트를 렌더링하고,

로딩이 끝났다면 데이터 여부에 따라 "있음" 또는 "없음"을 렌더링합니다.