์ ํ๋ก์ ํธ๋ ์ฐพ๊ณ ์ํ๋ ๋์์ ๋๋ฌผ์ ์ข ๋ฅ๋ฅผ ์ ํํ์ฌ ์ฐพ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ฐ์ธก์ ๋๋ฌผ์ 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๋ฅผ ์์ฑ ํ ์ ์๋ค !
'React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
You are running `create-react-app` 4.0.1, which is behind the latest release (4.0.3). ์ด์ ํด๊ฒฐ๋ฐฉ๋ฒ (0) | 2021.06.18 |
---|