본문 바로가기
내마음대로만들어보자/React

[Swipe] 우정테스트 사이트 만들기(Feat.리액트)

by 소농민! 2021. 8. 8.
728x90

첫번쨰로 Swipe를 이용해서 아래 동영상과 같이 퀴즈에 대한 문제를 풀수 있도록 움직여주는 부분을 만들어보자!

(이런 부분들은 공식문서를 참고하면은 참 쉽게 할 수있다는데 아직은 완벽하게 이해한게 아니다보니 공식문서도 어렵다ㅠㅠ)

반복하여 이해하는게 좋을 것 같다!!

 

1. 사전준비

패키지 설치하기 

 

yarn add react-tinder-card

 

Quiz.js에서 사용을 해야하므로 설치한 패키지를 임포트해오는걸 잊지말자!

import TinderCard from "react-tinder-card";

 

세부적인 내용은 공식문서 참고하자.

https://www.npmjs.com/package/react-tinder-card

 

react-tinder-card

A npm react module for making react elements swipeable like in the dating app tinder.

www.npmjs.com

 

2. 스와이프 적용 전 퀴즈문제 코드 수정  

- 우리가 작성한 퀴즈 문제는 총 4가지이므로, 문제들을 순서대로 보여주려면 스와이프가 되어야하는 영역에 map 돌려줘야한다.

 

<QuizContainer>

  ......

 {props.list.map((l, idx) => {

// 리스트 하나를 l 이라고하며, 리스트 하나에 대한 idx 를 가져온다.

        return (

         <DragItem key={idx}>

            <div>

              <img src={img}

           </div>

         </DragItem>

         ); 

 

  })}

</QuizContainer>

 

이렇게하면은 정상적으로 문제가 뜨는걸 볼 수 있다. 하지만, 맵을 돌려서 보여주다보니 여러개 중복되서 보여지게 된다.

이럴때 내가 풀고있는 문제에 해당하는 부분만 보여주도록 추가 작업을 해줘야한다.

 

state를 활용해서 문제 하나하나 넘어갈때마다 저장하도록 해보자.

 

const Quiz = (props) => {

    const [num, setNum] = React.useState(0);    

  }

....

 

<QuizContainer>

     <p>

   <span>{num+1}번 문제</span>

//몇번문제인지도 state에 저장한 넘버로 가져올 수 있다. index는 1번부터 시작이니까 +1 해주면 끝!

     </p>

 {props.list.map((l, idx) => {

          if(num === idx) {

                   return(<Question key={idx}>{l,question}</Question>);

           }

    })}

 

 {props.list.map((l, idx) => {

// 리스트 하나를 l 이라고하며, 리스트 하나에 대한 idx 를 가져온다.

       if(num === idx) {

          return (

         <DragItem key={idx}>

            <div>

              <img src={img}

           </div>

         </DragItem>

         ); 

      }

 

3. 스와이프 적용하기(Tinder-Card)

자세한 내용은 위에 공식문서를 참고해보자. 공식문서가 어렵더라도 시간될때마다 자주 읽어보자.

 

const onSwipe = (direction) => {

     console.log("You swiped: " + direction);

 }

return (

  <QuizContainer>

  ...

 

<DragItem>

    <TinderCard onSwipe={onSwipe}>

        <img src={img}

    </TinderCard>

</Dragitem

//기존 div를 스와이프 사용을 위해 TinderCard로 변경 

 

이렇게 코드를 변경해주면 이미지가 정상적으로 움직이는걸 볼 수 있다!

또한 개발자 콘솔에서 콘솔로그 찍은것처럼 "You swiped + direction" 을 볼수있다. right , left 등등 

 

이제 setNum 값을 통해 다음문제로 넘어갈 수 있도록 코드를 작성해보자.

 

const onSwipe = (direction) => {

     setNum(num+1);

     console.log("You swiped: " + direction);

 }

return (

  <QuizContainer>

  ...

 

스와이프하면은 정상적으로 다음문제로 넘어가는걸 볼 수 있다!

 

 

4. EventListner 적용하기

touch event 를 통해서 이벤트가 동작하도록 작업해보자.

https://developer.mozilla.org/ko/docs/Web/API/Touch_events

 

Touch events - Web API | MDN

터치를 기반으로 한 양질의 서비스를 제공하기 위해, Touch Events(터치이벤트)는 터치로 인한 움직임을 감지할 능력을 제공합니다.

developer.mozilla.org

 스와이프 Quiz.js 전체가 아닌 일부분에 대해서만 적용할거기때문에 새로운 파일을 만든다.

 

SwipeItem.js

* 기본 형태 

import React from "react";

import styled from "styled-components";

import img from "./scc_img01.png";

 

const SwipeItem = React.memo(({ onSwipe }) => {

         //memo는 memoization라고 불리우며, 간략하게 렌더가 여러번되는걸 방어해준다.

        <DragItem>

            <img src={img}

        </DragItem>

});

 

...

 

SwipeItem.defaultProps = {

onSwipe: (direction) => {},

};

// props를 받아서 쓸때 props가 없을때 에러가 나는걸 방지하기위해 props는 기본적으로 어떤값을 가지고있다고 알려주는 코드

 

export default SwipeItem;

 

 

이제 Quiz.js에서 가져다가 사용할 수 있도록 임포트해주자.

import SwipeItem from "./SwipeItem";

 

또, DragItem 부분은 SwipeItem에 불러와서 작성을 해주었기때문에 삭제해주고 아래와같이 작성해주면된다. 

{quiz.map((l, idx) => {

if (idx === num) {

return <SwipeItem key={idx} onSwipe={onSwipe}/>;

}

})}

 

이제는 터치이벤트를 만들어주면된다.

 

addEventListner 를 사용하기위해서 ref를 먼저 잡아주자.

 

* ref 사용예시

 - 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.

 - 애니메이션을 직접적으로 실행시킬 때.

 - 서드 파티 DOM 라이브러리를 React와 같이 사용할 때.

 

const swipe_div = React.useRef(null);

//함수형컴포넌트에서 ref잡는방법

 

...

 

return (

<DragItem ref={swipe_div}>

<img src={img} />

</DragItem>

);

});

 

useEffect를 통해서 이벤트리스너를 처음 한번만 등록을 해주면된다.

React.useEffect(() => {

 

};, []);

 // useEffect() 는 컴포넌트가 렌더링 될때마다 특정 작업을 실행할 수 있도록 해주는 훅이다!!

// useEffect() 안에 동작한 이벤트를 작성해준다.

 

const reset = () => {

}

const touchStart = (e) => {

}

const touchEnd = (e) => {

}

const touchMove = (e) => {

}

const touchCancel = (e) => {

}

 

// 필요한 이벤트 기본형태는 만들었으니, 이벤트 리스너를 등록하면된다.

swipe_div.current.addEventListener("touchstart", touchStart);

swipe_div.current.addEventListener("touchend", touchEnd);

swipe_div.current.addEventListener("touchmove", touchMove);

swipe_div.current.addEventListener("touchcancel", touchCancel);

 

항상 이벤트리스너를 등록해줬다면 해제도 해줘야한다.

return () => {

// 만약 이벤트 걸었던 엘리먼트가 없으면 해제하지 않는다!

if (!swipe_div.current) {

return;

}

swipe_div.current.removeEventListener("touchstart", touchStart);

swipe_div.current.removeEventListener("touchend", touchEnd);

swipe_div.current.removeEventListener("touchmove", touchMove);

swipe_div.current.removeEventListener("touchcancel", touchCancel);

};

 

 

기본형태가 준비가 되었다면 전체 완성한 코드에 대한 설명은 별도로 정리해보자!

처음부터 만드는건 어렵기때문에 하나하나보면서 어떤 원리로 동작하는지 이해하는데 집중하자.