[React] useState, useEffect, useRef을 이용하여 캐러셀 슬라이더 구현하기

go·2021년 7월 17일
20

React

목록 보기
8/15
post-thumbnail
post-custom-banner

React의 useState, useEffect, useRef을 이용하여 캐러셀 슬라이더를 만들어 보겠습니다.

1. Setting

create-react-app을 통해 리액트 프로젝트를 만들어 줍니다. 스타일링은 styled-components를 사용하겠습니다.

$ yarn create react-app react-carousel
$ yarn add styled-components

2. Slide.js 컴포넌트 추가

Slider의 요소가 될 Slide 컴포넌트를 만들어 줍니다.

import React from 'react';
import styled from 'styled-components';

export default function Slide({ img }) {
  return <IMG src={img} />;
}

const IMG = styled.img`
  width: 500px;
  height: 500px;
`;

이미지 파일을 props로 받고 보여줍니다.

3. Slider.js 파일 추가

1) import 하기

Slider.js 파일에 캐러셀에 들어갈 이미지들과

import img1 from './img/1.png'; 
import img2 from './img/2.png'; 
import img3 from './img/3.png';

이미지를 담을 Slide

import Slide from './Slide';

React Hooks, styled-components를 가져옵니다.

import React, { useState, useRef, useEffect } from 'react';
import styled from 'styled-components';

2) styled-components 를 통해 스타일링 하기

import React from 'react';
import styled from 'styled-components';
import Slide from './Slide';
import img1 from './img/1.png';
import img2 from './img/2.png';
import img3 from './img/3.png';

const Container = styled.div`
  width: 500px;
  margin: auto;
  height: 1000px;
  overflow: hidden; // 선을 넘어간 이미지들은 숨겨줍니다.
`;
const Button = styled.div`
  all: unset;
  padding: 1em 2em;
  margin: 2em 2em;
  color: burlywood;
  border-radius: 10px;
  border: 1px solid burlywood;
  &:hover {
    background-color: burlywood;
    color: #fff;
  }
`;
const SliderContainer = styled.div`
  margin: 0 auto;
  margin-bottom: 2em;
  display: flex; // 이미지들을 가로로 나열합니다.
`;
const Text = styled.div`
  text-align: center;
  color: burlywood;
  p {
    color: #fff;
    font-size: 20px;
    background-color: burlywood;
    display: inline-block;
    border-radius: 50px;
    padding: 0.5em 1em;
  }
`;
const Center = styled.div`
  text-align: center;
`;

const TOTAL_SLIDES = 2; // 전체 슬라이드 개수
export default function Slider() {
   return (
    <Container>
      <Text>
        <h1>호두 아가 시절</h1>
        <p>n번 째 사진</p>
      </Text>
      <SliderContainer>
        <Slide img={img1} />
        <Slide img={img2} />
        <Slide img={img3} />
      </SliderContainer>
      <Center>
        <Button>Prev</Button>
        <Button>Next</Button>
      </Center>
    </Container>
  );
}

3) 전체 슬라이드 개수 지정해주기

전체 슬라이드의 개수를 지정해 줍니다. 배열처럼 0부터 시작하여 총 3개의 이미지를 사용했으므로 TOTAL_SLIDES = 2를 추가해 줍니다.

const TOTAL_SLIDES=2 
  1. useState를 통해 현재 어떤 슬라이드를 보여주고 있는지 정합니다.
  2. nextSlide와 prevSlide를 통해 현재 보여주는 슬라이드를 정합니다.

4) useState를 통해 현재 어떤 슬라이드를 보여주고 있는지 나타내기

  const [currentSlide, setCurrentSlide] = useState(0);
  const slideRef = useRef(null);

5) nextSlide와 prevSlide를 통해 현재 보여주는 슬라이드 구현하기

if else 문을 통해 더 이상 넘어갈 슬라이드가 없을 경우 아래 2가지 방법을 사용하여 경우에 따라 다르게 사용할 수 있습니다.

  1. setCurrentSlide(0); 를 사용하여 1번째 사진으로 넘어갑니다.
  2. return; 를 사용하여 클릭이 작동하지 않습니다.

저는 1번째 사진으로 넘어가는 방식을 사용하였습니다.

// Next 버튼 클릭 시
  const NextSlide = () => {
    if (currentSlide >= TOTAL_SLIDES) {
      // 더 이상 넘어갈 슬라이드가 없으면
      setCurrentSlide(0); // 1번째 사진으로 넘어갑니다.
      // return;  // 클릭이 작동하지 않습니다.
    } else {
      setCurrentSlide(currentSlide + 1);
    }
  };
  // Prev 버튼 클릭 시
  const PrevSlide = () => {
    if (currentSlide === 0) {
      setCurrentSlide(TOTAL_SLIDES); // 마지막 사진으로 넘어갑니다.
      // return;  // 클릭이 작동하지 않습니다.
    } else {
      setCurrentSlide(currentSlide - 1);
    }
  };

  <Button onClick={PrevSlide}>Prev</Button>
  <Button onClick={NextSlide}>Next</Button>

6) useRef를 통해 Slider의 정보를 보여줍니다.

 useEffect(() => {
    slideRef.current.style.transition = 'all 0.5s ease-in-out';
    slideRef.current.style.transform = `translateX(-${currentSlide}00%)`; // 백틱을 사용하여 슬라이드로 이동하는 에니메이션을 만듭니다.
  }, [currentSlide]);

3. 전체 코드

Slider.jsx

import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import Slide from './Slide';
import img1 from './img/1.png';
import img2 from './img/2.png';
import img3 from './img/3.png';

const TOTAL_SLIDES = 2; // 전체 슬라이드 개수(총3개. 배열로 계산)

export default function Slider() {
  const [currentSlide, setCurrentSlide] = useState(0);
  const slideRef = useRef(null);

  // Next 버튼 클릭 시
  const NextSlide = () => {
    if (currentSlide >= TOTAL_SLIDES) {
      // 더 이상 넘어갈 슬라이드가 없으면
      setCurrentSlide(0); // 1번째 사진으로 넘어갑니다.
      // return;  // 클릭이 작동하지 않습니다.
    } else {
      setCurrentSlide(currentSlide + 1);
    }
  };
  // Prev 버튼 클릭 시
  const PrevSlide = () => {
    if (currentSlide === 0) {
      setCurrentSlide(TOTAL_SLIDES); // 마지막 사진으로 넘어갑니다.
      // return;  // 클릭이 작동하지 않습니다.
    } else {
      setCurrentSlide(currentSlide - 1);
    }
  };

  useEffect(() => {
    slideRef.current.style.transition = 'all 0.5s ease-in-out';
    slideRef.current.style.transform = `translateX(-${currentSlide}00%)`; // 백틱을 사용하여 슬라이드로 이동하는 에니메이션을 만듭니다.
  }, [currentSlide]);

  return (
    <Container>
      <Text>
        <h1>호두 아가 시절</h1>
        <p>{currentSlide + 1}번 째 사진</p>
      </Text>
      <SliderContainer ref={slideRef}>
        <Slide img={img1} />
        <Slide img={img2} />
        <Slide img={img3} />
      </SliderContainer>
      <Center>
        <Button onClick={PrevSlide}>Prev</Button>
        <Button onClick={NextSlide}>Next</Button>
      </Center>
    </Container>
  );
}
const Container = styled.div`
  width: 500px;
  margin: auto;
  height: 1000px;
  overflow: hidden; // 선을 넘어간 이미지들은 숨겨줍니다.
`;
const Button = styled.div`
  all: unset;
  padding: 1em 2em;
  margin: 2em 2em;
  color: burlywood;
  border-radius: 10px;
  border: 1px solid burlywood;
  cursor: pointer;
  &:hover {
    background-color: burlywood;
    color: #fff;
  }
`;
const SliderContainer = styled.div`
  margin: 0 auto;
  margin-bottom: 2em;
  display: flex; // 이미지들을 가로로 나열합니다.
`;
const Text = styled.div`
  text-align: center;
  color: burlywood;
  p {
    color: #fff;
    font-size: 20px;
    background-color: burlywood;
    display: inline-block;
    border-radius: 50px;
    padding: 0.5em 1em;
  }
`;
const Center = styled.div`
  text-align: center;
`;

App.js

import Slider from './Slider';
function App() {
  return (
    <div>
      <Slider />
    </div>
  );
}

export default App;
  • 해당 코드는 GitHub 에서 볼 수 있습니다.
  • 본 글은 peppermint100을 참고하여 작성되었음을 밝힙니다.
  • React를 공부하는 중이고, 복습하는 겸 포스팅을 하고 있기 때문에, 틀린 정보가 있을 수 있습니다.
    잘못된 정보가 있다면 댓글로 알려주세요 :)
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 9월 11일

호두 넘 귀엽네요ㅎㅎ 참고해서 만들어볼게요~친절한 설명 감사합니다!

답글 달기