스켈레톤 컴포넌트란?

데이터를 가져오는 동안 콘텐츠의 영역을 나타내는 컴포넌트로 스켈레톤 애니메이션을 화면에 노출하여 사용자의 요청을 처리하고 있다는 메시지를 줍니다.

웹 사이트 접속 시 로딩 중인 것을 알려주는 로딩바처럼 사용할 수 있습니다.

네이버 메일 스켈레톤 UI

네이버 메일 스켈레톤 UI

유튜브 스켈레톤 UI

유튜브 스켈레톤 UI

여기서 단순 콘텐츠 영역만 표시할 수도 있고 애니메이션 효과를 줄 수도 있습니다.

아래 실습은 애니메이션 효과를 넣은 컴포넌트로 만들어 보겠습니다.

const Container = () => {
    const [isLoading, setLoading] = useState(true);

    useEffect(() => {
        setTimeout(() => {
            setLoading(false);
        }, 5000);
    }, []);

  return (
    <>
      {isLoading ?
          <Skeleton/>
          : (
          <li className='item-container'>
              <div>
                  <div className='item-img'/>
              </div>
              <div className='item-info'>
                  <p className='item-info-text'>
										texttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                  </p>
                  <p className='item-info-text'>
	                  texttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                  </p>
              </div>
          </li>
      )}
    </>
  )
}

const App = () => {
  return <Container/>;
}

먼저 로드가 끝났을 때 보여줄 컴포넌트의 구조를 살펴 보겠습니다.

li.item-container 내 이미지, 텍스트로 구성되어 있습니다.

.item-container {
    width: 500px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px;
    margin: 30px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

.item-container .item-img {
    width: 80px;
    height: 80px;
    background: cadetblue;
    border-radius: 50%;
}

.item-container .item-info {
    width: 400px;
}

로드 후 컴포넌트

로드 후 컴포넌트

이제 스켈레톤 컴포넌트 로직을 작성해보도록 하겠습니다. 먼저, 구조는 로드 후 컴포넌트와 동일하게 짜야 합니다.

function Skeleton (){
    return(
        <li className='item-container-skeleton'>
            <div>
                <div className='item-img-skeleton'/>
            </div>
            <div className='item-info-skeleton'>
                <p className='item-info-text-skeleton'/>
                <p className='item-info-text-skeleton'/>
            </div>
        </li>
    )
}
@keyframes loading {
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(460px);
    }
}

/* skeleton */
.item-container-skeleton {
    width: 500px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px;
    margin: 30px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

.item-container-skeleton .item-img-skeleton::before {
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: linear-gradient(to right, #eee, #ddd, #eee);
    animation: loading 2s infinite linear;
}

.item-container-skeleton .item-img-skeleton {
    width: 80px;
    height: 80px;
    background: #eee;
    border-radius: 50%;
    position: relative;
    overflow: hidden;
}

.item-container-skeleton .item-info-skeleton {
    width: 400px;
}

.item-container-skeleton .item-info-skeleton .item-info-text-skeleton::before {
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: linear-gradient(to right, #eee, #ddd, #eee);
    animation: loading 2s infinite linear;
}

.item-container-skeleton .item-info-skeleton .item-info-text-skeleton {
    width: 100%;
    height: 20px;
    background: #eee;
    position: relative;
    overflow: hidden;
}

로드 전 컴포넌트(스켈레톤 UI)

로드 전 컴포넌트(스켈레톤 UI)

스켈레톤 컴포넌트를 작성해주었고 애니메이션까지 적용한 후 App.js 컴포넌트에서 setTimeout으로 3초 후 로드시킵니다.