Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- react portal
- 향해99
- Node
- JS
- NVM
- CPU와 GPU의 차이점
- 원티트 프리온보딩인턴십 1주차
- 알고리즘
- Passed by Value
- Mac OS NVM
- 광고지구
- 식별자란
- toast err
- JavaScript
- jsEvent Loop
- 회고록
- Til
- input error
- 원티드인턴십
- 인풋태그 엔터
- Client-Side Navigation
- git
- 원티드프리온보딩
- react
- NextJs
- 유령 의존성
- 프로젝트
- Redux
- CloudFront 무효화
- next/link
Archives
- Today
- Total
SUIN
[React] 타입스트립트로 스켈레톤 구현하기 본문
728x90
스켈레톤이란
웹페이지에서 로드 시간이 짧아 보이게 하는 몇 가지 방법 중 하나가 스켈레톤이다
데이터가 로드되기 전에 컨텐츠의 자리비움을 표시하여 사용자가 기다리는 시간을 덜 지루하게 하는 ui이다
장점
- 실제 테스트 결과 블랭크 페이지 < 스피너 < 스켈레톤 순서대로 더 빠르다고 느끼게 된다.
단점
- 스켈레톤을 화면마다 표시해야하기때문에 시간이나 비용이 많이 든다.
실생활에서 볼수있는 스켈레톤 예시
스켈레톤 규칙
-
스켈레톤은 콘텐츠의 로드를 방해하면 안된다!실제 콘텐츠는 데이터를 가용할 수 있는 시점이 되면 즉시 스켈레톤을 대체해야함
-
디자인 할 때 애니메이션을 사용하는 것이 좋다애니메이션은 wave, pulse 중 wave 를 사용하는 것이 로딩 시간을 더 짧게 느끼게끔 한다.
-
느리고 안정적인 애니메이션을 사용하는 것이 로딩 시간을 더 짧게 느끼게끔 한다
타입 스크립트로 스켈레톤 만들어보기
스켈레톤 컴포넌트
interface Props {
width?:number;
height?:number;
circle?:boolean; //원형 스켈레톤
rounded?:boolean; //모서리
unit?:string; //px or % 단위
animation?:boolean; //애니메이션 유무
color?:string;
style?:React.CSSProperties; //스켈레톤의 추가적인 스타일객체
}
//pulseKeyframe
const pulseKeyframe = keyframes`
0% {
opacity: 1;
}
50% {
opacity: 0.4;
}
100% {
opacity: 1;
}
`;
//pulseAnimation
const pulseAnimation = css`
animation: ${pulseKeyframe} 1.5s ease-in-out 0.5s infinite;
`;
const Base = styled.span<Props>`
${({color}) => color && `background-color: ${color}`};
${({rounded}) => rounded && `border-radius: 8px`};
${({circle}) => circle && `border-radius: 50%`};
${({width, height}) => (width || height) && `display: block`};
${({animation}) => animation && pulseAnimation};
width : ${({width, unit}) => width && unit && `${width}${unit}`};
height : ${({height, unit}) => height && unit && `${height}${unit}`};
`;
const Content = styled.span`
opacity: 0;
`;
const Skeleton: React.FC<Props> = ({
animation = true,
children,
width,
height,
circle,
rounded,
unit = 'px',
color = '#F4F4F4',
style,
}) => {
const styles ={
style:style,
rounded:rounded,
circle:circle,
width:width,
height:height,
animation:animation,
unit:unit,
color:color,
}
return (
<Base {...styles}>
<Content></Content>
</Base>
);
};
App.tsx
function App() {
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
// 임의로 로딩 상태 표현
setTimeout(() => setLoading(false), 3000);
}, []);
return (
<Base>
{
loading ? Array.from({ length: 25 }).map((_, idx) => (
<Placeholder key={idx} />
)) : Array.from({ length: 25 }).map((_, idx) => (
<Item key={idx} />
))
}
</Base>
);
}
// 스켈레톤 UI
const Placeholder: React.FC = () => ( // <Item /> 에 대응하는 Placeholder 제작
<Container>
<ImageWrapper>
<Skeleton height={220} />
</ImageWrapper>
<Info>
{/* Title */}
<Skeleton width={150} height={29} rounded />
<div style={{ height: '8px' }} />
{/* Description */}
<Skeleton width={200} height={19} rounded />
</Info>
</Container>
)
const Item: React.FC = () => ( // 실제 보여줄 컨텐츠
<Container>
<ImageWrapper>
{/* 더미데이터 */}
<Image src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSVqiN6h4EBIKut_XAn4KxgJKNNrY8LcFZq7Q&usqp=CAU" />
</ImageWrapper>
<Info>
<Title>제목입니다.</Title>
<Description>신이난다 신이나~신이난다 신이나~</Description>
</Info>
</Container>
)
구현화면
'React' 카테고리의 다른 글
react-router-dom v6 <Outlet> 적용해보기 (0) | 2022.12.28 |
---|---|
[React] 조건부 랜더링 (0) | 2022.02.24 |
[React] 멀티 element 생성해보기 (React.Fragment를 쓰는 이유 ) (0) | 2022.02.07 |
[Raact] JSX 란 (0) | 2022.02.07 |
[React] React DOM 다루기 (JSX 없이 element 그려보기) (0) | 2022.02.07 |