TypeScript React를 이용한 간단한 이미지 슬라이더 만들기 📑

yiyb0603·2021년 2월 9일
2

React

목록 보기
9/13
post-thumbnail

안녕하세요! 오늘은 TypeScript React를 이용한 간단한 이미지 슬라이더를 만들어 볼 것입니다. 위의 썸네일 사진이 저희가 만들어볼 이미지 슬라이더의 모습 인데요, 내용은 크게 어렵지 않으니까 쉽게 따라오실 수 있을거에요! 😀😀

1. 임의의 데이터 추가

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',
];

2. 컴포넌트 생성

이제 이미지 슬라이더를 보여줄 컴포넌트를 작성해보겠습니다. 이전까지 저는 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;

스타일링을 모두 끝내고 나면 아래와 같이 화면이 설계되어 있습니다.

3. 화살표 클릭 구현하기

가장 먼저, 양 옆에 위치한 화살표 버튼을 클릭하면 이미지의 순서가 변경되도록 하는 기능을 구현하도록 하겠습니다. 단순 순서변경 기능은, 몇가지의 예외들만 처리 해주고나면 간단하게 구현이 됩니다. 아래 두개의 함수들을 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으로 속성을 전달한 다음에 실행해보세요! 화살표를 눌렀을 때, 이미지들이 알맞게 잘 바뀌나요? 😀

4. 점을 클릭하여 이동 구현하기

지금까지 화살표를 클릭하여 이미지 순서 바꾸기를 구현해보았으니, 마지막으로 아래 사진의 점을 클릭하여 이미지가 변경되는 기능을 추가해보도록 하겠습니다. 😀

아래의 코드들을 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일때만 바뀝니다. 😀

5. 글을 마치며 📑

해당 이미지 슬라이더는 저의 포트폴리오 사이트의 프로젝트 소개 모달창에서 구현하여 현재까지 잘 쓰고 있는 이미지 슬라이더 입니다. 포트폴리오 사이트에 넣으려고 작업을 시작했을때, 처음에는 조금 까다로운 작업일 것 이라고 생각하고 시작을 했었는데, 제가 생각했던 로직들만 이용해서 쉽게 구현할 수 있었습니다.

예제를 따라 해보시면서 궁금한점이 있다면 댓글로 달아주세요!
이상으로 글을 마치도록 하겠습니다. 긴 글 읽어주셔서 감사합니다! 😁

profile
안녕하세요

0개의 댓글