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

[EventListener 코드설명] 우정테스트 사이트 만들기(Feat.리액트)

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

* SwipeItem.js 전체코드

import React from "react";
import styled from "styled-components";
import img from "./scc_img01.png";

//memoziation 은 여러번 랜더가 이루어지지않게 방어해준다고 보면된다. React.memo()
const SwipeItem = React.memo(({ onSwipe }) => {
const swipe_div = React.useRef(null);
//함수형컴포넌트에서 ref잡는법

// 현재 swipe 상태
let swipe_status = "ready";
//나중에 이친구가 애니메이팅 효과를 주기위해 미리 작성한 코드 (스와이프했을때 자연스럽게 움직이게 하기위함)
let target_classname = "";
//시작위치를 기록해놔야 이벤트가 동작할때 기록을 하기위함  (터치시작을 기록한 변수를 선언한 코드)

let coordinate = {
start_x: 0,
start_y: 0,
end_x: 0,
end_y: 0,
};

//useEffect를 통해 이벤트리스너는 처음한번만 등록해주면된다. 처음 한번만 등록할때는 대괄호도 붙여줘야한다.
React.useEffect(() => {
const reset = () => {
// console.log("in reset");
swipe_status = "ready";

coordinate = {
start_x: 0,
start_y: 0,
end_x: 0,
end_y: 0,
};

swipe_div.current.className = target_classname;

swipe_div.current.style.left = 0 + "px";
swipe_div.current.style.top = 0 + "px";
};
//리셋에서는 coordinate, className, left,top 모두 원래대로 돌려놓아야한다. 초기값으로 

const touchStart = (e) => {
// e 라는건 이벤트 객체를 가져온다고 보면된다. 

// 터치 시작 시, swipe_status를 touchstart로 변경해줍니다.
// 그리고 터치 시작한 좌표를 기록합니다!
// (중요! 그래야 터치 종료할 때 위치를 보고 왼쪽인지, 오른쪽인지 판별할 수 있다!)
swipe_status = "touchstart";
target_classname = swipe_div.current.className;
// console로 터치 이벤트가 시작될 때 좌표를 확인해볼까요?
// console.log(e.touches[0]);
// console.log(e.touches[0].clientX);
// console.log(e.touches[0].clientY);

// 좌표도 기록해줍니다 :)
coordinate = {
...coordinate,
start_x: e.touches[0].clientX,
start_y: e.touches[0].clientY,
};
};

const touchEnd = (e) => {
swipe_status = "touchend";
// touchEnd이벤트는 touches 대신, changedTouches가 있어요.
// console.log(e.changedTouches[0]);
coordinate = {
...coordinate,
end_x: e.changedTouches[0].clientX,
end_y: e.changedTouches[0].clientY,
};

// x좌표 이동 거리를 구해줍니다.(x좌표에 대한 차이를 구해야하므로 비교해주면된다)
let diff_x = coordinate.end_x - coordinate.start_x;
// 스와이프 방향 / 기본은 left로 뒀습니다!
let direct = "left";

// Match.abs() : 절대값을 구해주는 친구입니다.
// 기존에 className에 swipe라는 className를 추가해주겠다는 의미이며, 
// 아래 &.swipe {} 이런식으로 연결하여 추가로 SCSS문법에 따라 꾸며줄 수 있다.
if (Math.abs(diff_x) > 50) {
swipe_div.current.className = target_classname + " swipe";

// 움직인 방향에 따라 더 옴직이고 투명도를 0으로 (점점 사라지게) 줘봐요!
if (diff_x > 0) {
// console.log('move right');
direct = "right";
//이벤트 동작 후 한번에 이동하지않고 부드럽게 이동될 수 있도록 함 
swipe_div.current.style.left = diff_x + 150 + "px";
swipe_div.current.style.opacity = 0;
} else {
direct = "left";
// console.log('move left');
// console.log(diff_x - 150);
swipe_div.current.style.left = diff_x - 150 + "px";
swipe_div.current.style.opacity = 0;
}

// 300 ms후 reset 해줍니다!
// 이 300ms는 props로 받아서 처리해줘도 좋겠네요!
// props로 받아온, 콜백 함수도 여기서 처리해줄게요!
window.setTimeout(() => {
reset();   //터치무브하면서 움직여놓은게 있기때문에 리셋을 한번 해줘야한다. 
onSwipe(direct);
}, 300);
return;
}

// reset 해줍니다.
reset();
};

const touchMove = (e) => {
// 스와이프 중 다른 이벤트가 발생하는 것을 막아줍니다
e.preventDefault();

// console.log("in touch move!");
// 현재 좌표(이동 중인 좌표)를 기록해준다. 이미지가 이동할때 기록된 좌표를 토대로 움직여주기위해 
let current_coordinate = {
x: e.touches[0].clientX,
y: e.touches[0].clientY,
};

// 콘솔로 이동한 값이 어떻게 나오는 지 한번 확인해볼까요?
// console.log(
// current_coordinate.x - coordinate.start_x,
// current_coordinate.y - coordinate.start_y
// );

// 터치 중일 때 div가 따라 움직이도록 해주는데 움직인만큼만 움직이도록 한다. 
swipe_div.current.style.left =
current_coordinate.x - coordinate.start_x + "px";
swipe_div.current.style.top =
current_coordinate.y - coordinate.start_y + "px";
};

// 터치 이벤트가 취소될 경우 원래 상태로 돌려줍니다!
const touchCancel = (e) => {
swipe_status = "cancel";
reset();
};

//터치이벤트 등록 해주는 부분(이벤트 리스너) 
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);
};
}, []);

return (
<DragItem ref={swipe_div}>
<img src={img} />
</DragItem>
//DragItem 에서 swipe를 적용하려고하는것이므로, 여기에다가 ref 먼저 잡아줘야한다. 
);
});

const DragItem = styled.div`
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;

&.swipe {
transition: 300ms;
}

& > div {
border-radius: 500px;
background-color: #ffd6aa;
}
& img {
max-width: 150px;
}
`;

SwipeItem.defaultProps = {
onSwipe: (direction) => {},
};
// props가 없을때 화면에서 에러가나는걸 방지하기위해 기본적으로 이 props는 어떤값을 가지고 있다라고 알려준다. 

export default SwipeItem;