IT/React
[React] Skeleton UI 구성하기
HJ::
2023. 9. 11. 17:21
사용 이유
컨텐츠를 불러오는 동안 사용자로 하여금 지루함을 느끼게 하지 않고, 데이터를
불러오는 중임을 나타내주기 위해 빈 UI를 구성해서 불러오는 동안 틀에 맞춰 띄워준다.
불러오는 중임을 나타내주기 위해 빈 UI를 구성해서 불러오는 동안 틀에 맞춰 띄워준다.
미리보기
제품 유무별 상태 관리
// PostCards.tsx
const [_, setIsLoading] = useAtom(isLoadingAtom);
// 데이터 유무에 따른 전역 상태 관리(Main.tsx- skeleton UI)
useEffect(() => {
if (posts) setIsLoading(false);
}, [posts]);
useEffect(() => {
if (!posts) setIsLoading(true);
}, [posts]);
- react-redux와 같은 기능인 jotai라이브러리를 사용해서 전역 상태 관리 처리를 해줬습니다.
- post 데이터가 없을 때는 Loading을 true로 기본값 설정해주고 posts를 가져오게 되면 false로
isLoading을 false상태로 해주었습니다.
// Main.tsx
export const isLoadingAtom = atom<Boolean>(true);
...
<>
{/* 데이터 불러올때 스켈레톤 UI */}
{isLoading && (
<>
{Array.from({ length: 5 }).map((_, index) => (
<PostSkeleton key={index} />
))}
</>
)}
...
- 변수로 받은 isLoading이 true/false 임에 따라 Skeleton컴포넌트를 랜더링 할지 결정해줍니다.
// ProdList.tsx
const [isProdLoading, setIsProdLoading] = useState<Boolean>(true);
useMemo(() => {
if (productList) setIsProdLoading(false);
}, [productList])
...
{/* 제품 불러올때 스켈레톤 UI */}
{isProdLoading && (
<>
<ProdSkeleton />
</>
)}
- 이건 제품 스켈레톤 구성인데 한 코드에서 작동될 수 있으므로 useState만 사용해주었습니다.
- useMemo는 react 훅 중 하나로 함수의 결과 값을 저장하고,
함수의 입력 값이 변경되지 않으면 이전 결과를 반환합니다.
그래서 productList가 들어오기 전과 들어오고 나서 총 2번만 수행합니다.
Styled-components로 css 구성하기
// styleBox.ts
export const SkeletonItem = styled.div`
width: 100%;
height: 30px;
background-color: #f2f2f2;
position: relative;
overflow: hidden;
border-radius: 4px;
@keyframes skeleton-gradient {
0% {
background-color: rgba(165, 165, 165, 0.1);
}
50% {
background-color: rgba(165, 165, 165, 0.3);
}
100% {
background-color: rgba(165, 165, 165, 0.1);
}
}
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
animation: skeleton-gradient 1.5s infinite ease-in-out;
}
`;
...
<>
<S.Container>
{Array.from({ length: 12 }).map((_, index) => (
<S.EmptyBox key={index} />
))}
</S.Container>
</>
...
EmptyBox: styled(SkeletonItem)`
width: calc(25% - 30px); /* 4 columns with 30px gap in between */
height: 250px;
border-radius: 10px;
margin-bottom: 30px;
`
- SkeletonItem 은 시간에 따른 애니매이션 효과를 주기 위함입니다.
- 적절한 크기를 분배해서 화면에 원하는 개수만큼 리스트로 화면에 띄어줍니다.