첫 번째 팀 프로젝트 후기

Seoyong Lee·2021년 8월 2일
0

etc.

목록 보기
6/10

첫 번째 팀 프로젝트를 잘 마무리 했다. 작업 내용과 이를 통해서 배우게 된 사실을 정리해 보았다.

결과물

Codestory 링크

게임으로 배우는 코딩이라는 주제로 리눅스 CLI를 GUI로 보여주는 게임 사이트를 만들었다. 나는 프론트엔드를 담당하였으며, 주로 랜딩 페이지 애니메이션과 전체적인 컴포넌트의 틀을 잡는 역할을 하였다. 또한 CSS를 전담하여 처음으로 프로젝트의 뷰를 구성해보았다. 추가로 디자인 툴 사용에 부담이 없었기 때문에 자연스럽게 캐릭터(물론 리눅스 펭귄 tux는 옛 로고를 참고하였다)나 favicon 등의 이미지 제작 또한 담당하게 되었다.

과정

기획 및 와이어프레임 설계

기획 단계에선 다음과 같은 요소들을 고려하였다.

  1. 2주라는 짧은 일정 때문에 높은 완성도를 추구하기 보다는 구현이 가능한 새로운 기능을 제작해보자.
  2. 프로젝트 결과물로 자주 보이는 기능이 거의 없는 사이트 제작이나 클론코딩은 피하자.
  3. 실질적인 도움이 되는 유용한 기능을 개발하자.

이를 종합하여 고민한 결과 코딩 교육이라는 주제를 도출할 수 있었고, 이를 '시각화' 한다면 교육 효과가 높아지지 않을까? 라는 아이디어가 나오게 되었다.

이를 토대로 기본적인 화면 설계는 다음과 같이 진행하였다.

왼쪽 화면에서 게임에 대한 설명과 입력 창을 구현하고, 오른쪽 화면을 통해 결과물을 확인해보는 구조로 설계하였다. 입력한 값을 서버에 보내 정답 여부만 돌려줄 수 있다면 이에 맞춰서 화면의 배치를 바꾸는 식으로 진행할 수 있을 것이라 예상하였다.

기술 스택

스택은 첫 프로젝트인 만큼 지금까지 배운 내용을 복습한다고 생각하고 최소한의 기술만을 이용했다. 프론트 쪽은 axios와 react-router-dom 정도를 이용해서 기본적인 통신과 페이지 이동을 구현하고, 추가적으로 랜딩 페이지 애니메이션을 위해 Animate.css 기반의 WOW.js 라이브러리를 사용하였다. 리덕스는 아직 복잡한 상태 관리가 필요하지 않을 것 같아서 추가하지 않았다. 서버와 배포 관련된 부분은 AWS에 관심이 많은 다른 팀원들의 도움을 많이 받았다. 또한 ESLint를 통해서 초반에 세미콜론과 인덴트 등 기본적인 컨벤션을 통일하고 시작하였다.

컴포넌트 구성 및 react-router-dom 연결

처음엔 일단 프론트 쪽에서 필요한 모든 컴포넌트와 이를 react-router-dom으로 연결하는 작업부터 진행하였다. 그 뒤 컴포넌트의 기본적인 박스 틀을 잡고, CSS를 구성하여 서버쪽의 API 코드가 완성되기 전까지 최대한 기본적인 외형을 잡으려 노력하였다.

CSS의 레이아웃 방법은 flexbox와 grid 사이에서 고민하다가 일단 flex를 완벽하게 이해해보자는 생각으로 모두 flexbox를 중심으로 작업하였다. 덕분에 이제 박스 배치와 관련된 고민은 거의 하지 않고도 원하는 위치에 요소를 쉽게 배치할 수 있게 되었다.

랜딩 페이지와 애니메이션

사실 랜딩 페이지는 서비스의 얼굴인 만큼 매우 공을 들인 부분이었다. 특히 페이지의 스크롤 위치에 따라서 버튼을 나타나게 한다던가, 특정 위치로 보내는 등의 기능을 구현하기 위해서는 스크롤 위치를 인식하는 함수가 필수적이었다.

이는 스택 오버플로우의 도움으로 다음과 같이 설정하였다.

const [y, setY] = useState(null);

  useEffect(() => {
    window.addEventListener('scroll', 
      (e) => handleNavigation(e));
    return () => { 
      window.removeEventListener('scroll', 
      (e) => handleNavigation(e));
    };
  }, [y]);

일단 현재 y의 좌표를 state로 설정한 후, 이를 이벤트 리스너를 통해 handleNavigation 함수에 전달한다. 여기서 return()과 같은 클린업을 이용해 removeEventListener를 실행해 주어야 정상적으로 작동한다는 점을 처음 알게 되었다.

  const handleNavigation = (e) => {
    const window = e.currentTarget.scrollY;
    console.log(window);
    if (window >= 650 && window < 2000) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
    setY(window.scrollY);
  };

현재 좌표를 전달받은 handleNavigation 함수는 좌표를 기반으로 버튼을 보여주고 숨기는 함수를 실행한다. 또한 setY를 통해 y를 설정하여 useEffect가 y의 변화에 따라 실행되도록 값을 남겨준다. 이러한 방식을 통해 특정 위치에서만 화면 밑으로 보내는 '게임 시작' 버튼을 보이게 할 수 있었다. 또한 글자를 누르면 정확히 다음 글자위치로 보내는 함수를 다음과 같이 구성하였다.

 const move1 = () => {
    window.scrollTo({
      top: document.getElementById('landing-page-2')
      	.offsetHeight,
      behavior: 'smooth'
    });
  };

처음엔 절대적인 좌표로 이동하도록 하였으나 화면 크기에 따라 위치가 달라지는 문제가 발생하여 위와 같이 전체 랜딩페이지를 5개의 페이지로 분할하고, 특정 페이지의 높이만큼 상대적으로 이동하도록 하였다.

애니메이션을 위해선 WOW.js라는 가벼운 라이브러리를 사용해 보았는데 실제 조작이 되지 않아서 불편하였다. 다음 프로젝트에선 GSAP을 이용해 직접 조작해 보려한다.

로딩 인디케이터

로딩 인디케이터는 useEffect를 이용해 isLoading이라는 상태를 변형시켜 작동하도록 하였고, CSS의@keyframes 를 이용해서 원의 색을 변하게 하는 방식으로 제작하였다.

.nav-loading-circle {
  margin-left: .4rem;
  width: 1rem;
  height: 1rem;
  border-radius: 1rem;
  animation: color-change .4s infinite;
}

@keyframes color-change {
  0% { background-color: #232321; }
  50% { background-color: #ffffff; }
  100% { background-color: #fccb03; }
}

사실 다른 메뉴 영역에도 플레이스 홀더를 배치하였으면 어땠을까 하는 아쉬움이 남는다.

아쉬웠던 점

반응형에 대한 고민

사실 반응형 구현은 초반에는 화면 구성의 제약때문에 깊이 생각해 보지 못한 부분이었다. 뒤늦게 CSS 기준을 vw, vh 및 %로 변경하려 하였으나 모바일 반응형은 구현하지 못하였다. 다음 프로젝트 에서는 꼭 도전해 보려 한다.

상태 관리 및 props 설정

사실 이번 프로젝트를 처음 시작할 때 state와 이를 기반으로 props를 주고받는 구조에 대해서 깊이 생각해 보지 않았던 것 같다. 이는 자연스럽게 app.js에 모든 상태가 몰려 복잡하게 엉키는 결과로 돌아왔고 이는 다음 프로젝트에선 고쳐야 할 부분이라고 생각된다. 처음부터 견고한 계획 위에서 작업을 진행했다면 특정 컴포넌트 내에서 불필요한 정보는 전달하지 않도록 설계되었을 것 같아서 아쉬움이 남는 부분이다.

후기

사실 처음 해보는 프로젝트라 큰 기대 없이 배운것들을 복습하면서 완성만 하자는 마음으로 시작하였다. 그러나 팀원분들이 너무 열심히 해주셔서 좋은 결과물을 만들어 낼 수 있었다. 사실 게임이라는 주제를 정했을 때도 이게 가능할까? 싶었지만 모든지 계획만 잘 짠다면 구현할 수 있다는 점을 깨달았다.

이제 조금은 리액트를 자유롭게 가지고 놀아 본 것 같다. 이제 바닥에서 부터 컴포넌트를 설계하고, 거기에 CSS와 상태를 붙인 앱을 만들 수 있게 되었다. 앞으로 진행할 프로젝트에서 생각하는 모든 것들을 구현할 수 있다니 기대가 된다. 파이널 프로젝트에서도 좋은 결과물을 낼 수 있길 바란다.

profile
코드를 디자인하다

0개의 댓글