[project] 사이트에 skeleton을 적용해보자

didio·2023년 3월 15일
0

project

목록 보기
4/7

skeleton이란?

데이터가 렌더링 되기 전에 화면에 표시될 데이터들의 윤곽을 나타내는 UI이다. 데이터가 불러와지기 전에 어떤 것들이 불러와질지 예층할 수 있다.

유튜브에 접속 했을 때도 skeleton ui가 적용되어 있다. 유튜브의 데이터가 로딩되기 때지 로딩중이라는 표시가 없다면 사용자들은 어떤 내용이 화면에 뿌려질지 예측하지 못하고, 로딩시간이 길어진다면 사용자들을 웹사이트를 이탈 할 수도 있다.

skeleton을 어떤 상황에 적용할까?

  • 비동기 데이터 요청을 하여 로딩 상황이 발생 했을 때 약 1초 이상의 시간이 걸리는 경우
    1초 미만이 소요되는 상황에서는 로딩중 ui를 설정한다면 산만해지는 느낌을 줄 수 있다. 1초이상 로딩중이 발생하는 경우에 사용하여 요청이 진행중임을 표시한다.

프로젝트에 적용해보기

도서 검색 사이트에서는 검색 바에 도서를 검색하면 도서목록이 출력된다. 키보드입력 변화에 대해서 debounce를 걸어 키보드 입력이 0.8초이상 나타나지 않는다면 Api가 요청 되도록 했다.
키보드를 입력 할때부터 검색결과가 나올 때까지 0.8초 이상이 걸리므로 로딩중 ui를 적용하여 사용자가 입력을 하면서 부터 요청이 진행중임을 나타내고 싶었다.
loading의 상태를 변경하여 true이면 skeleton을 보여주고, false이면 데이터나 검색결과가 없다는 안내 문구가 나오도록 설정 했다.

📌 고려 사항

  • 첫번째 요청 페이지에만 skeleton을 적용한다.
  • 키보드 입력이 시작 되면 loading상태를 true로 변경한다.
  • api가 요청되고 도서 데이터를 bookList에 저장을 한뒤 loading상태를 false로 변경한다. (비동기 처리)
  • 검색어가 없을 경우에는 loading상태를 false로 변경한다.

📍skeleton 구성

//Skeleton.js
export default function Skeleton({ size }: SizeType) {
  let skeletonArr = Array.from({ length: size });
  return (
    <Container>
      <Row xs="3">
        {skeletonArr.map(() => (
          <>
            <SkeletonSection>
              <ImageDiv></ImageDiv>
              <InfoP></InfoP>
              <InfoP></InfoP>
            </SkeletonSection>
          </>
        ))}
      </Row>
    </Container>
  );
}

📍 skeleton css

const SleletonAnimation = keyframes`
   0% {
        background-color: rgba(165, 165, 165, 0.1);
    }

    50% {
        background-color: rgba(165, 165, 165, 0.3);
    }

    100% {
        background-color: rgba(165, 165, 165, 0.1);
    }

`;
const SkeletonSection = styled.section`
  margin-top: 40px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
`;
const ImageDiv = styled.div`
  width: 120px;
  height: 150px;
  background-color: #f5f5f5;
  border-radius: 10px;
  animation: ${SleletonAnimation} 1.8s infinite ease-in-out;
`;
const InfoP = styled.div`
  width: 120px;
  height: 20px;
  background-color: #f5f5f5;
  border-radius: 10px;
  text-align: left;
  animation: ${SleletonAnimation} 1.8s infinite ease-in-out;
`;
//Main.js
{loading ? (
        <Skeleton size={size} />
      ) : (
        <ItemList book={bookList} imgRef={setLastBook} />
      )}

📍 로딩 상태를 변화시킨 부분

//searchInput.js
// input창에 변화가 생기면 loading 상태를 true로 변화시킨다.
const onChangeInputs = (e: React.ChangeEvent<HTMLInputElement>) => {
    setLoading(true);

    if (timer) {
      clearTimeout(timer);
    }
    const newTimer = setTimeout(async () => {
      try {
        await setSearchValue(e.target.value);
      } catch (e) {
        console.error(e);
      }
    }, 800);
    setTimer(newTimer);
  };
  //Main.js
  // api요청이 끝나고 데이터가 다 불러오면 lodaing을 false로 바꾼다.
  // 검색어가 "" 비어있다면 loading 상태를 false로 변화시킨다.
   useEffect(() => {
    if (searchValue) {
      bookSearchHandler(searchValue, sortel[sort], 1, size)
        .then((res) => getBookList(res.documents))
        .then(() => setLoading(false));
    } else if (!searchValue) {
      getBookList([]);
      setLoading(false);
    }
  }, [searchValue, sort]);

❌ 적용전

⭕️ 적용후

skeleton을 적용할때와 아닐때 비교를 해보니 적용한 것이 사용자에게 더 좋은 경험을 줄 수 있는 것을 알았다.

다음 프로젝트에서는 Suspense를 사용하여 데이터를 불러볼 것이다.

참고 사이트
https://tech.kakaopay.com/post/skeleton-ui-idea/

profile
🌈프론트엔드 공부 기록

0개의 댓글