React로 Skeleton UI 만들기

2021-11-29


위 프로젝트는 찾고자하는 도시와 동물의 종류를 선택하여 찾기 버튼을 누르면 우측에 동물의 Data를 보여주는 프로젝트이다

서버에서 동물의 Data를  받아오기 전에 우측 화면에 아무런 UI가 없다면 사용자는 콘텐츠를 기다리다가 쉽게 지루함을 느낄 수 있고

단순히 흰색 화면만 보여준다면 많은 사람들은 사이트를 떠나게 될 것이다.

이 전에는 Loading bar 또는 Loading Spinner 등이 쓰였는데 최근 핫하다는 웹 페이지들은 모두 Skeleton을 사용하는 것 같다

더 나은 UX를 위해서 Skeleton UI 를 배워보자


import axios from 'axios';
import React, { useEffect, useState } from 'react';
import Skeleton from './Skeleton';

const List = () => {
  const [list, SetList] = useState([]);

  useEffect(() => {
    setTimeout(async () => {
      try {
        const response = await axios('url/list');
        const data = response.data;
        SetList(() => {
          return list.concat(data);
        });
      } catch {
        throw new Error('데이터 조회 실패');
      }
    }, 1000);
  }, []);

  return (
    <div>
      // list가 있다면 list 렌더링 없다면 Skeleton 렌더링
      {list ? list.map((listItem) => <div>{listItem}</div>) : <Skeleton />}
    </div>
  );
};

export default List;

위의 코드는 axios로 Data를 받아와 list State에 받아온 Data를 저장하고 list 가 있으면 list를 렌더링하고 없다면 Skeleton 컴포넌트를

렌더링하는 코드이다


import React from 'react';
import * as style from './SkeletonStyle';
import theme from '../../assets/styles/theme';

function Skeleton() {
  return (
    <style.Div theme={theme}>
      <style.Img theme={theme}>
        <style.Shimmer />
      </style.Img>
      <style.Wrap theme={theme}>
        <style.Text theme={theme}>
          <style.Shimmer />
        </style.Text>
        <style.Text theme={theme}>
          <style.Shimmer />
        </style.Text>
        <style.Text theme={theme}>
          <style.Shimmer />
        </style.Text>
      </style.Wrap>
    </style.Div>
  );
}

export default Skeleton;

Skeleton 컴포넌트의 코드를 살펴보자 여기서 주목해야할 것은 Shimmer의 역할이다

Shimmer는 각 엘리먼트 안에 포함되어 그림자가 흐르는 듯한 애니메이션을 보여준다



그림자가 흐르는 듯한 역할을 하는 것이 Shimmer의 역할이다

CSS 코드를 보면서 살펴보자


import styled from 'styled-components';

export const Shimmer = styled.div`
  width: 50%;
  height: 100%;
  background-color: #e0e0e0;
  box-shadow: 0 0 30px 30px #e0e0e0;
  animation: loading 2s infinite;
  @keyframes loading {
    0% {
      transform: translateX(-50%);
    }
    50% {
      transform: translateX(100%);
    }
    100% {
      transform: translate(200%);
    }
  }
`;

export const Div = styled.div`
  display: flex;
  flex-direction: column;
  width: 150px;
  height: 200px;
  margin: 1em;
  border: 1px solid #e8e7e6;
  border-radius: 0.5em;
  font-size: 0.7em;
  overflow-x: visible;
  cursor: pointer;
  background-color: white;
  box-shadow: 6px 6px 8px 0px rgba(217, 217, 217, 1);
`;

export const Img = styled.div`
  width: 100%;
  height: 150px;
  border-top-left-radius: 0.5em;
  border-top-right-radius: 0.5em;
  overflow: hidden;
  background-color: #eeeeee;
`;

export const Wrap = styled.div`
  display: flex;
  justify-content: center;
  flex-direction: column;
  padding: 0.4rem;
`;

export const Text = styled.div`
  width: 100px;
  height: 10px;
  margin-bottom: 5px;
  overflow: hidden;
  background-color: #eeeeee;
`;

각 엘리먼트들은 div 태그로 생성되어 있으며 Data가 들어와 채워야할 자리에 임의로 크기를 지정하여 색을 입힌 것이다

그리고 그 엘리먼트 내부에 Shimmer 엘리먼트를 삽입하여 애니메이션이 나오도록 하는 것이다

Shimmer는 무한으로 상위 엘리먼트를 순환하며 애니메이션을 보여주고 Shimmer를 감싼 부모 태그에는 overflow: hidden 을 줘서

Shimmer가 부모 태그 밖에서 보이지 않도록 막아준다

위의 코드로 Skeleton을 만들면 하나의 list 밖에 나오지 않지만 Skeleton 컴포넌트 안에 있는 엘리먼트의 수를 늘린다면 원하는 만큼의 Skeleton UI를 생성 할 수 있다 !

© 2024 SongChangYeop All rights reserved