[zerobase team-project] react-shop 4주차

Mayton·2022년 9월 5일
0

제로베이스

목록 보기
9/13
post-thumbnail

3주차가 비어버린 이유...?

약 2주간 현역으로의 마지막 훈련을 하고 왔다... 그동안 지하에서 아무런 통신이 안되는 채 2주간 먹고 자고 했기 때문에 git에 있는 잔디에도 또한번의 38선이 그어졌다. 상반기에는 다시 마음을 잡고, 돌아오는 데 시간이 많이 걸렸지만 이번에는 그럴만한 여유도 시간이 없다. 여러가지 하반기 지원이 시작되고 있고, 나는 코테라도 보고, 떨어지더라도 면접이라도 봐서, 내 실력과 위치를 확인하고 싶기 때문이다.

Slider Component

두번째 세션에서 조언을 받아 Animation으로 동작하는 것으로 변경하였다.

transition이란 CSS 프로퍼티의 값이 변화할때, 프로퍼티 값의 변화가 일정 시간에 걸쳐 일어나도록 하는 것으로, 상태 변화에 동반하여 변경되는 CSS 프로퍼티 값에 의한 표시의 변화를 부드럽게하기 위해 애니메이션 속도를 조절한다. hover와 click과 같은 trigger가 필요하다.

Animation 이란 CSS 스타일을 다른 CSS 스타일로 부드럽게 변화시키며, trigger가 없어도, @keyframes 들로 이루어져있으며, 세부 움직임을 시간 흐름 단위로 제어할 수 있고, 전체 줄거리의 재생과 정지, 반복까지 제어할 수 있다.

이런 면을 보았을 때, 자동으로 slider를 넘어가는 부분을 구현하고, 추가적으로 동작하는 animation을 변경하기 위해서는 animation이 적합해보였다.

animation으로 동작하는 법

변수는 moveClass, moveAuto, carouselItems 세가지를 선언했다.
moveClass는 animation이 동작할 때 ul tag 내에 들어갈 className, moveAuto를 통해 자동으로 넘기는 것을 제어고, carouselItems는 이미지들이 들어가 있는 state이다.

  const [moveClass, setMoveClass] = useState('');
  const [moveAuto, setMoveAuto] = useState(true);
  const [carouselItems, setCarouselItems] = useState<Image[]>(images);

carouselItems 내 첫 이미지만 화면에 보이게 되고, Next, Prev 버튼을 누르면 carouselItems 내의 item이 제일 뒤로 가거나 뒤의 이미지가 제일 앞으로 오게 된다.
그리고 버튼 클릭 시에는 ul tag내의 className 인 moveClass 내에 next, prev 클래스를 넣어주게 된다.

  const shiftPrev = (copy: Image[]) => {
    let lastcard = copy.pop();
    if (lastcard) {
      copy.splice(0, 0, lastcard);
      setCarouselItems(copy);
    }
  };

  const shiftNext = (copy: Image[]) => {
    let firstcard = copy.shift();
    if (firstcard) {
      copy.splice(copy.length, 0, firstcard);
      setCarouselItems(copy);
    }
  };

<PrevBtn
	onClick={() => {
		if (moveAuto) handleCheck();
		setMoveClass('prev');
	}}
>    
<NextBtn
	onClick={() => {
		if (moveAuto) handleCheck();
        setMoveClass('next');
	}}
>

이 때 className을 자유롭게 바꿀 수 있는 것이 StyleComponent의 장점이라고 할 수 있다.

      <SliderList
        className={`${moveClass}`}
        onAnimationEnd={handleAnimationEnd}
      >

그리고 onAnimationEnd의 애니메이션이 끝났을 때, className을 다시 빈 값으로 변경해주면 animation이 종료된다.

  const handleAnimationEnd = () => {
    if (moveClass === 'prev') {
      shiftNext([...carouselItems]);
    } else if (moveClass === 'next') {
      shiftPrev([...carouselItems]);
    }
    setMoveClass('');
  };

CSS 에서 animation에 대한 keyframes를 아래와 같이 설정하면, 조금 더 자연스러운 애니메이션을 구현할 수 있었다.

.next {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.83, 0, 0.17, 1);
  animation-name: next;
}

@keyframes next {
  from {
    transform: translateX(0px);
  }
  to {
    transform: translateX(calc(0px + var(--cardWidth)));
  }
}

자동으로 슬라이더를 구현하는 부분은 customHook을 이용하였는데, 그 이유는 추가로 포스팅하도록 하겠다.
아래의 useInterval이 사용한 customHook이고, handleCheck을 이용해, moveAuto를 전환하여 자동으로 슬라이더가 넘어가는 것을 종료 및 시작 할 수 있었다. (Next, Prev 버튼을 누를 때 자동전환을 종료하고, 이미지 위에 hover 될 시에 자동전환을 종료 하였다.)

  useInterval(
    () => {
      setMoveClass('next');
    },
    moveAuto ? delay : null
  );

  const handleCheck = () => {
    setMoveAuto(!moveAuto);
  };

issue

잘 되는 것 같던 애니메이션이 중반 이후부터 갑자기 안듣기 시작했다. 이유를 확인해 보니, styled-component의 변수들 때문이었다.

아래와 같이 변수들을 slider component 안에서 선언을 해서, moveClass의 값이 변경되어 리렌더링되어도, 변경된 값이 아니라, 원래부터 있던 값처럼 생각되어 애니메이션도 동작하지 않고, animationEnd도 당연히 동작하지 않았다.

const SliderSection = tw.section`
w-full relative overflow-x-hidden slidersection
`;

const SliderList = tw.ul` relative flex slider 
`;

const NextBtn = tw.button`
  absolute h-full w-8 top-0 right-0  bg-transparent hover:bg-gray-500 hover:bg-opacity-25 hover:ease-in duration-200
`;

const PrevBtn = tw.button`
absolute h-full w-8 top-0 left-0 bg-transparent hover:bg-gray-500 hover:bg-opacity-25 hover:ease-in duration-200
`;

const Slider = ({ images }: { images: Image[] }) => {
  const [moveClass, setMoveClass] = useState('');
  const [moveAuto, setMoveAuto] = useState(true);
  const [carouselItems, setCarouselItems] = useState<Image[]>(images);

위와 같이 변경해 주면 되는데, 혹시 그 전에 transition때의 문제도 위와 같지 않았나 생각해보고 있다.

컴포넌트 내에서도 반복을 줄이자

최초에 이슈를 해결을 하게된 이유는 React의 useMemo, useCallback을 사용하는 것에 관한 책을 보고 있다가, 어느정도 리팩토링을 하면서 하자는 마음에서, 다시 Slider 컴포넌트를 바라보았더니, issue에 관한 것이 눈에 들어왔다.

애초에 styled-components의 변수들이 slider 안에 선언이 되어있으면, 변동되지 않는 값인데도 리렌더링이 될때마다 다시 선언되어야 한다. 함수들 조차 리렌더링 시에 재 선언되지 않기 위해서, useCallback을 사용하는데 외부에서 선언되도 전혀 지장이 없는 변수들 같은 경우에는 당연히 외부에서 선언해 주면 되겠다.

Vercel 배포

git을 내가 계속 관리해와서, 내가 없는 2주동안 깃이 PR만 올라오고 그대로였다. 그래서 지난번까지 작업된 내용들을 merge 해서, vercel로 배포하였다.

이때 organization으로 따로 만들어서 repository를 생성했는데, 이 경우에는 vercel에서 유료로 제공을 하고있다. 이럴 때에는 개인 repository로 fork 해온 뒤에 master 브랜치를 vercel에 연결하면 배포에 성공할 수 있다! 그런데 vercel을 속이는 방법이 아니라, vercel에서 이런 방식으로 진행할 수 있게 유도해 주고 있었다.

Import a Third-Party library를 선택하고, 이때 입력한 주소가 다른 organization에서 만들어진 깃이라면, fork 해서 개인 repository에서 배포할 수 있도록 바로바로 도와준다.

이 때 우리의 프로젝트는 아직 리팩토링도 해야하고, 업데이트 할 것이 주구장창 남았는데, 배포를 하고 싶고, 업그레이드 할 때마다 그럼 우리가 다시 fork 해주거나, 업데이트 해주어야 하나? 하는 의문점을 가지게 되었다. 검색해보니 git Action을 사용해서, 자동으로 일정한 시간에 업데이트 시켜 줄 수 있었다. 운영체제의 cron과 같은 기능을 사용하는 것이다.

ref: [https://stackoverflow.com/questions/23793062/can-forks-be-synced-automatically-in-github]

react에서 image를 가져오는 방법

배포를 하고 난 뒤에 배포한 페이지에서 image를 가져오지 못하는 현상이 발생했다. 특히 slider들이 모두 사진이 엑스박스가 나타났다.

  1. src 폴더에서 이미지를 import
    • js 안에서 import를 통해 경로를 작성한다.
      import imgLogo from "./imgTest.jpg";

  2. public 폴더에서 가져오기
    • public 폴더 아래에 이미지를 넣어 놓게 되면, url에 http:// localhost:3000/img/imgTest.jpg와 같이 절대경로로 입력해주면 된다.

1과 같은 방법으로 변경하고, 문제를 해결할 수 있었다.

import vegetableImg from '../assets/images/vegetables.jpeg';
import shopImg from '../assets/images/shop.jpeg';
import jeanImg from '../assets/images/jeans.jpeg';

const Index = () => {
  return (
    <Slider
      images={[
        {
          url:  vegetableImg,
          title: 'hihi',
          description: 'hello',
        },
        {
          url: shopImg ,
          title: 'hihi',
          description: 'hello',
        },
        {
          url: jeanImg ,
          title: 'hihi',
          description: 'hello',
        },
      ]}
    />
  );
};

아쉬운 점

배포된 사이트

아직 리팩토링 해야할 부분이 너무나도 많은 건 확실 하기에, 더 리팩토링을 해야한다.

최소한

  • 주석 달아놓은 것 모두 지우기
  • 자신이 한 부분 리드미 작성하기

여기에 구현한는 부분, 자신이 한부분 설명하는 부분까지 영상 제작하여 올리고 싶지만, 아직 클론 코딩이기에 다음번에 해보겠다!

profile
개발 취준생

0개의 댓글