안녕하세요! 오늘은 TypeScript React를 이용한 간단한 이미지 슬라이더를 만들어 볼 것입니다. 위의 썸네일 사진이 저희가 만들어볼 이미지 슬라이더의 모습 인데요, 내용은 크게 어렵지 않으니까 쉽게 따라오실 수 있을거에요! 😀😀
src 디렉토리에 data 라는 폴더를 만든다음, Image.ts라는 파일을 만들어 줍시다. 이 파일 안에는 임의의 사진 URL 배열을 넣어줍니다. 저는 Velog 글들에 있는 이미지 URL들을 가져왔습니다. 😀
// Image.ts
export const images: string[] = [
'https://media.vlpt.us/images/holim0/post/7d80e99d-11bc-4327-b16d-324a8daa0014/image.png',
'https://media.vlpt.us/images/wooder2050/post/3c21dfdf-67b9-4301-8c25-e505303e246a/og-image.png',
'https://media.vlpt.us/images/edie_ko/post/4631c9fc-fa76-47e9-9d77-bc160476c60a/1_mv73TpGPVFXzJqu920m5Og.png',
'https://media.vlpt.us/images/dongha1992/post/2efd8b1b-d186-40bc-a574-026f180750ba/react.jpeg',
'https://media.vlpt.us/images/kimhodol/post/9c9e0ba3-20b1-4ba9-9a66-9af9ab5cf2e6/hodol-typescript.jpg',
];
이제 이미지 슬라이더를 보여줄 컴포넌트를 작성해보겠습니다. 이전까지 저는 scss를 사용하여 스타일링을 진행해왔는데, 이번에는 @emotion/react를 사용하려고 해보았지만, 설정 등의 문제로 인해서 emotion과 유사한 styled-components를 사용하여 스타일링을 진행했습니다.
src 디렉토리에 components 폴더를 만든 뒤, 아래와 같이 컴포넌트 파일들을 추가하였습니다.
이제 ImagePicker.tsx에 스타일링 코드들을 작성해주겠습니다. 저는 아래와 같이 추가해주었어요. 😀
// ImagePicker.tsx
import React, { useState } from 'react';
import styled from 'styled-components';
import { AiOutlineArrowLeft, AiOutlineArrowRight } from 'react-icons/ai';
import { images } from 'data/Images';
const Container = styled.div`
width: 800px;
height: 500px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
`;
const FillImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`;
const PickerWrapper = styled.div`
position: absolute;
left: 50%;
bottom: 10px;
transform: translate(-50%, -10px);
display: flex;
`;
const Arrow = styled.div<{ isLeft: boolean }>`
width: 50px;
height: 50px;
background-color: gray;
border-radius: 50%;
position: absolute;
top: 50%;
${(props) => props.isLeft ? 'left: 5px' : 'right: 5px'};
transform: translate(-5px, -50%);
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
color: white;
cursor: pointer;
`;
const Picker = styled.div<{ background: string }>`
width: 12px;
height: 12px;
border-radius: 50%;
background-color: ${(props) => props.background};
margin: 0 6px;
cursor: pointer;
`;
const ImagePicker = (): JSX.Element => {
const [pickers, setPickers] = useState<JSX.Element[]>([]);
// 이미지 순서를 클릭하여 이동하는 pickers 배열
const [pickIndex, setPickIndex] = useState<number>(0);
// 기본으로 0번째 인덱스에 위치한 사진을 렌더링
return (
<Container>
<FillImage src={images[pickIndex]} />
{/* pickIndex라는 state 변수를 이용하여 그에 맞는 이미지 렌더링 */}
<Arrow isLeft={true} onClick={handlePrevClick}>
<AiOutlineArrowLeft />
</Arrow>
<Arrow isLeft={false} onClick={handleNextClick}>
<AiOutlineArrowRight />
</Arrow>
<PickerWrapper>
</PickerWrapper>
</Container>
);
};
export default ImagePicker;
스타일링을 모두 끝내고 나면 아래와 같이 화면이 설계되어 있습니다.
가장 먼저, 양 옆에 위치한 화살표 버튼을 클릭하면 이미지의 순서가 변경되도록 하는 기능을 구현하도록 하겠습니다. 단순 순서변경 기능은, 몇가지의 예외들만 처리 해주고나면 간단하게 구현이 됩니다. 아래 두개의 함수들을 ImagePicker.tsx에 추가해주세요! 😀
// 왼쪽 화살표 클릭
const handlePrevClick = useCallback((): void => {
if (pickIndex <= 0) {
// state 업데이트 전, 해당 변수의 값이 0이라면
setPickIndex(images.length - 1);
// length의 -1로 지정하여 가장 마지막으로 이동한다.
return;
}
setPickIndex(pickIndex - 1);
// 인덱스 감소
}, [pickIndex]);
// 오른쪽 화살표 클릭
const handleNextClick = useCallback((): void => {
if (pickIndex + 1 === images.length) {
// +1 했을 때, 배열의 인덱스를 벗어난다면
setPickIndex(0);
// 0으로 설정하여 가장 첫번째로 이동
return;
}
setPickIndex(pickIndex + 1);
// 인덱스 증가
}, [pickIndex]);
위의 함수들을 Arrow 컴포넌트에 onClick으로 속성을 전달한 다음에 실행해보세요! 화살표를 눌렀을 때, 이미지들이 알맞게 잘 바뀌나요? 😀
지금까지 화살표를 클릭하여 이미지 순서 바꾸기를 구현해보았으니, 마지막으로 아래 사진의 점을 클릭하여 이미지가 변경되는 기능을 추가해보도록 하겠습니다. 😀
아래의 코드들을 ImagePicker.tsx에 추가해주세요!
const onPickIndex = useCallback((idx: number): void => {
if (pickIndex === idx) {
// 선택되어 있는 인덱스를 클릭시에는 아무것도 실행하지 않는다.
return;
}
setPickIndex(idx);
}, [pickIndex]);
useEffect(() => {
// 이미지의 갯수만큼 pickers JSX.Element[] 배열 state에 생성하여 넣어준다.
setPickers(images.map((_: string, idx: number) => {
return (
<Picker
onClick={() => onPickIndex(idx)}
background={pickIndex === idx ? 'orange' : 'white'}
{/* state pickIndex와 자신의 idx가 같을시 색깔을 다르게 준다. */}
>
</Picker>
);
}));
}, [onPickIndex, pickIndex]);
JSX를 return 하는 코드에서 아래와 같이 수정해주세요.
<Container>
<FillImage src={images[pickIndex]} />
<Arrow isLeft={true} onClick={handlePrevClick}>
<AiOutlineArrowLeft />
</Arrow>
<Arrow isLeft={false} onClick={handleNextClick}>
<AiOutlineArrowRight />
</Arrow>
<PickerWrapper>
{pickers}
{/* 위에서 선언해준 pickers JSX.Element[]들을 렌더링
map을 해주지 않아도 렌더링이 됨 (JSX.Element[]의 특성인것 같다.) */}
</PickerWrapper>
</Container>
코드를 모두 작성하시고 나서 저장을 하고 실행해보세요! 아래와 같은 결과가 나타나나요?
화살표를 클릭했을때는 아래의 점 색깔이 똑같은 idx일때만 주황색으로 바뀝니다. 😀
점을 클릭했을때는 올바른 순서의 이미지를 띄워주고, 점 색깔도 그에 맞는 idx일때만 바뀝니다. 😀
해당 이미지 슬라이더는 저의 포트폴리오 사이트의 프로젝트 소개 모달창에서 구현하여 현재까지 잘 쓰고 있는 이미지 슬라이더 입니다. 포트폴리오 사이트에 넣으려고 작업을 시작했을때, 처음에는 조금 까다로운 작업일 것 이라고 생각하고 시작을 했었는데, 제가 생각했던 로직들만 이용해서 쉽게 구현할 수 있었습니다.
예제를 따라 해보시면서 궁금한점이 있다면 댓글로 달아주세요!
이상으로 글을 마치도록 하겠습니다. 긴 글 읽어주셔서 감사합니다! 😁