Language/React
React 라이브러리 없이 캐러셀 구현하기
conqueror-G
2022. 11. 28. 22:00
애니메이션 없는 캐러셀
SKill | 사용이유 |
Emotion | CSS Prop을 사용하기 위해서 |
React | - |
Typescript | 버그 방지 |
import { Fragment, ReactNode, useState } from "react"
// 더미 데이터
const dummyData = Array.from({ length: 22 }).map((_,index) =>({
name: `obj${index + 1}`
}))
// 메인 컴포넌트
const Home = () => {
// 슬라이드 넘길 때 showCount만큼 +
const [ currentSlide, setCurrentSlide ] = useState<number>(0)
// 총 데이터의 개수
const slideCount = dummyData.length
// 화면에 보여주고 싶은 개수
const showCount = 4
// 슬라이드 아이템 개수 조절
const filterData = dummyData.filter((_, index) => index >= currentSlide && index < currentSlide + showCount)
// 다음으로 넘기기 함수
const handleArrowButtonNext = () => {
setCurrentSlide(currentSlide + showCount)
}
// 이전으로 넘기기 함수
const handleArrowButtonPrev = () => {
setCurrentSlide(currentSlide - showCount)
}
return (
<Card css={{
position: 'relative',
display: 'flex'
}}>
<PrevArrowButton currentSlide={currentSlide} onClick={handleArrowButtonPrev} />
<Item data={filterData} />
<NextArrowButton
currentSlide={currentSlide}
showCount={showCount}
slideCount={slideCount}
onClick={handleArrowButtonNext}
/>
</Card>
)
}
export default Home
interface CardProps {
children: ReactNode
className?: string
}
// Card( Wrapper )
const Card = ({ children, className }: CardProps) => {
return (
<div css={{
boxSizing: 'border-box',
padding: 10,
borderRadius: 10,
backgroundColor: '#d9d9d9',
}}
className={className}
>
{children}
</div>
)
}
interface ItemProps {
data: {
name: string
}[]
}
// Item( 이미지나 등등 )
const Item = ({ data }: ItemProps) => {
return (
<Fragment>
{ data.map((el) => (
<div
key={el.name}
css={{
position: 'relative',
flex: 1,
height: '100%',
margin: '0 10px'
}}>
<div css={{
position: 'absolute',
left: 0,
right: 0,
top: 0,
backgroundColor: '#00000099'
}}>
{ el.name }
</div>
<div css={{
height: 300,
backgroundColor: 'lightgreen'
}} />
</div>
)
)}
</Fragment>
)
}
interface NextArrowButtonProps {
/**
* @optional
*
* @description
*
*/
className?: string
/**
* @requierd
*
* @description
* Arrow button에 대한 onClick 기능
*/
onClick: React.MouseEventHandler<HTMLButtonElement>
/**
* @requierd
*
* @description
* 슬라이드 총 아이템 개수
*/
slideCount: number
/**
* @requierd
*
* @description
* 페이지네이션 같은 개념으로 이해
* 0에서 시작
* 한번 슬라이드를 넘기면,showCount 만큼 증가,
* (slideCount % showCount === 0)이면, ( 최대 값이 slideCount - 5 )
* (slideCount % showCount !== 0)이면, 최대 값이 slideCount
*/
currentSlide: number
/**
* @required
*
* @description
* 한 화면 안의 아이템 개수
*/
showCount: number
}
// 슬라이드 다음으로 넘기기 버튼
const NextArrowButton =
({ className, onClick, slideCount, currentSlide, showCount }: NextArrowButtonProps) => {
/**
* @description
* 조건 1: 데이터가 딱 떨어지지 않을 때
* !(slideCount - currentSlide < showCount)
* 조건 2: 데이터가 딱 떨어질 때
* currentSlide !== (slideCount as number) - showCount
*/
return (
<Fragment>
{currentSlide !== (slideCount as number) - showCount &&
!(slideCount - currentSlide < showCount) && (
<button
className={className}
onClick={onClick}
css={{
zIndex: 10,
position: 'absolute',
top: '50%',
right: 30,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 30,
height: 30,
borderRadius: '50%',
border: 'none',
backgroundColor: 'white',
transform: 'translateY(-50%)',
cursor: 'pointer',
}}
>
{`>`}
</button>
)}
</Fragment>
)
}
interface PrevArrowButtonProps {
/**
* @description
*
*/
className?: string
/**
* @requierd
*
* @description
* 페이지네이션 같은 개념으로 이해
* 0에서 시작
* 한번 슬라이드를 넘기면,showCount 만큼 증가,
* (slideCount % showCount === 0)이면, ( 최대 값이 slideCount - showCount )
* (slideCount % showCount !== 0)이면, 최대 값이 slideCount
*/
currentSlide: number
/**
* @requierd
*
* @description
* Arrow button에 대한 onClick 기능
*/
onClick: React.MouseEventHandler<HTMLButtonElement>
}
// 슬라이드 이전으로 넘기기 버튼
const PrevArrowButton =
({ className, currentSlide, onClick }: PrevArrowButtonProps) => {
return (
<Fragment>
{currentSlide !== 0 && (
<button
className={className}
onClick={onClick}
css={{
zIndex: 10,
position: 'absolute',
top: '50%',
left: 30,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 30,
height: 30,
borderRadius: '50%',
border: 'none',
backgroundColor: 'white',
transform: 'translateY(-50%)',
cursor: 'pointer',
}}
>
{`<`}
</button>
)}
</Fragment>
)
}
타입스크립트네.. 에이 어려워 넘겨!가 아니라 타입 부분만 제거하고 사용해보십시오.
주석을 달아놓긴 했으나, 코드가 너무 어렵다면 일단 복사해가서 이것저것 만져보세요!