๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

React

React๋กœ Skeleton UI ๋งŒ๋“ค๊ธฐ

์œ„ ํ”„๋กœ์ ํŠธ๋Š” ์ฐพ๊ณ ์žํ•˜๋Š” ๋„์‹œ์™€ ๋™๋ฌผ์˜ ์ข…๋ฅ˜๋ฅผ ์„ ํƒํ•˜์—ฌ ์ฐพ๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์šฐ์ธก์— ๋™๋ฌผ์˜ 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๋ฅผ ์ƒ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค !