skeleton ui

heyj·2022년 3월 12일
2

wanted_PreOnboarding

목록 보기
4/7

검색어를 입력하면 해당 검색어가 포함된 git repository를 화면에 보여주도록 하는 과제가 생겼습니다.

skeleton ui?

skeleton ui는 데이터가 화면에 로딩되기 전 사용자에게 화면이 로드 중임을 나타내기 위해 사용하는 UI입니다. 아마 대부분의 사용자들이 로딩중임을 나타내는 여러 ui를 경험했을 것입니다.

skeleton ui는 말 그대로 컨텐츠의 뼈대, 구조만 보이는 ui입니다. 페이스북이나 유튜브 로딩화면에서 많이 접하셨을 거예요.

프로젝트에 skeleton ui 적용하기

1. 검색이 되면 나오는 item컴포넌트

Item 컴포넌트는 검색결과 list에 각 width 45%씩 차지하도록 배치했습니다.

import React from 'react';
import styled from 'styled-components';

const ItemCard = (props) => {
  return (
    <Item
      onClick={selectRepo}
      able={props.repo.open_issues > 0 ? 'able' : 'unable'}
      >
      <User>
        <UserProfile
          src={`http://github.com/${props.repo.owner.login}.png`}
          />
        <UserName>{props.repo.owner.login}</UserName>
        {props.repo.open_issues > 0 ? '' : <NoIssues>No Issues</NoIssues>}
      </User>
      <Repository>{props.repo.name}</Repository>
      {props.repo.language && (
        <LanguageInfo>
          Language: <Language>{props.repo.language}</Language>
        </LanguageInfo>
      )}
    </Item>
};

const Item = styled.li`
  list-style: none;
  margin: 3px;
  padding: 6px;
  width: 45%;
  border: 1px solid #ddd;
  border-radius: 10px;
  background-color: ${(props) => (props.able === 'able' ? 'white' : '#f0f0f0')};
  overflow: hidden;
  &:hover {
    background-color: ${(props) =>
      props.able === 'able' ? '#00a0ff10' : '#f0f0f0'};
    cursor: ${(props) => props.able === 'able' && 'pointer'};
  }
`;

2. 적용하기

로딩중이라는 ui를 적용하기 전에는 대기 시간이 제법 길게 느껴집니다.
아이템들이 하나의 덩어리이고 issue가 없는 repository는 배경색이 다르기 때문에 item 전체를 skeleton ui로 표현하기로 결정했습니다.

아무것도 없는 컴포넌트에 스타일만 해줬습니다.
검색 대기 시간이 길지 않지만 시각적 효과를 위해 간단한 애니매이션을 추가해줬습니다.

빈 배열을 돌아 렌더링 할 수 있도록 검색 결과수와 동일한 빈 배열을 만들었습니다.

const emptyData = () => {
  let result = [];
  for (let i = 0; i < 30; i++) {
    let empty = '';
    result.push(empty);
  }
  return result;
};

const loadingData = emptyData();
import styled, { keyframes } from 'styled-components';

const Skeleton = (props) => {
  return <Item />;
};

export default Skeleton;

const fade = keyframes`
  from {
    opacity: 0.1;
  }
  to {
    opacity: 1;
  }
`;

const Item = styled.li`
  list-style: none;
  margin: 3px;
  padding: 6px;
  height: 92px;
  width: 45%;
  border-radius: 10px;
  background-color: #f1f1f1;
  animation: ${fade} 1s infinite;
`;

search 컴포넌트에서는 state로 isLoading의 상태를 관리해주며, api를 호출하는 순간 true로, 불러온 데이터가 setState로 저장이 되면 false로 바꿔주며 화면에 보여주도록 했습니다.

3. 완성

검색을 기다리는 시간이 조금 덜 지루해진 느낌입니다.

4. 데이터 로딩 시간이 길다면

만약 받아올 데이터 양이 많아 로딩시간이 길어진다면 아래와 같은 애니메이션을 추가해도 괜찮을것 같습니다.

export default function Loading() {
  return <div className="skeleton"></div>;
}

.skeleton {
  margin: auto;
  width: 500px;
  height: 500px;
  
  background-image:
    linear-gradient( 90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.5) 40%, rgba(255, 255, 255, 0) 90% ),
    linear-gradient(#ddd 80px, transparent 0);
  
  background-repeat: repeat-y;
  
  background-position:
    5px 10px,
    5px 10px;

  background-size:
    200px 100px,
    200px 100px;
  animation: light 2s infinite;
}

@keyframes light {
  to {
    background-position:
      100% 10px,
      5px 10px,
      5px 70px;
  }
}

0개의 댓글