2차 프로젝트 종료 회고록

박희주·2022년 7월 17일
0
post-thumbnail

2차 프로젝트 회고

👉 프로젝트 기간: 22년 7월 4일 ~ 22년 7월 15일
👉 프로젝트 명: GREENEEDS
👉 프로젝트 REPO: 34-2nd-greeeneeds-frontend
👉 프로젝트 소스: Tumblbug
👉 프로젝트 구성원: 프론트엔드 4명, 백엔드 2명

  • 홈페이지 최종 결과물(gif)
    GREENEEDS.gif

  • 프로젝트 팀원 사진
    팀원-사진

  • 프로젝트간 활용 협업 Tool

    • Trello
      Trello
    • Notion
      Notion

1. 주요 구현 목표

1️⃣ Nav, Footer: Nav에 로그인이 되었을때와 아닐때 구분해서 기능구현
2️⃣ Login: 소셜로그인(kakao)을 활용한 로그인 페이지 구성하기

1-1. Nav

Nav는 로그인이 됐을 때와 안됐을 때를 컴포넌트 구분지어 만들었다.
차이점은 로그인이 됐을 땐 유저의 정보를 받아 로그인 버튼에 유저의 이름이 나오도록 구현하였고 안됐을 땐 로그인 버튼으로 클릭시 로그인 페이지로 넘어가게 구현했다.

  • 로그인 안됀 Nav(Nav.js)

    // Nav내에서 navigate가 여기서만 쓰이는것이 아니기에
    // navigate 훅을 하나로 활용하기 위해 새로운 함수를 제작
    // 가야될 페이지를 인자로 받기
    const movePage = path => {
      navigate(path);
    };
    
    // 로그인이 안돼있을 때 클릭 시 로그인 페이지로 이동
    <GoToLogin
      onClick={() => {
        movePage('/login');
      }}
    >
      <ProfileIcon src="images/Nav/profileIcon.png" alt="profile" />
      <LoginButton>로그인/회원가입</LoginButton>
    </GoToLogin>
    • 로그인이 안됐을 때의 Nav에 로그인버튼을 클릭했을때는 Login페이지로 이동하게끔 기능을 구현함
  • 로그인 됀 Nav(LoggedInNav.js)

    <UserOption
      onClick={() => {
        showOptions();
      }}
    >
      <ProfileIcon src="images/Nav/profileIcon.png" alt="profile" />
      {userData && <UserName>{userData.nickname}</UserName>}
    </UserOption>
    {isShowOption && <ProfileOptionBlock onLogOut={onLogOut} />}
    • 로그인이 됐을 때는 로그인 유저의 정보를 받아 nickname이라는 데이터를 렌더링하도록 구현
  • 로그인이 됀 상태에서 UserOptionBlock을 만들어서 로그아웃 버튼을 만들어 로그아웃 기능을 적용하였다.

    // Nav.js
    // Nav.js에서 로그아웃 기능을 하는 함수를 만들어서
    const onLogOut = () => {
      localStorage.removeItem('token');
    };  
    
    // LoggedInNav.js
    // LoggedInNav.js에 props로 전달하였다.
    <LogoutButton
      onClick={() => {
        onLogOut();
      }}
    >
      로그아웃
    </LogoutButton>

Footer는 초기 기획단계에서 기능은 모두 빼고 레이아웃만 잡는것으로 결정돼 크게 어려움을 느낀 작업은 아니었다.

1-3. Login

Kakao Developers에 가입하여 로그인 API에 내 프로젝트를 만들어서 지금 하고있는 팀 프로젝트에 적용하였다.
KaKaoDev

  • 사이트 도메인을 프론트엔드에서 작업중인 http://localhost:3000으로 등록했다.

    • 소셜로그인을 구현하는 블로그 글과 공식 문서를 참조해보니 추후 REDIRECT URI를 반드시 프론트엔드에서 접근이 가능한 PORT로 맞춰줘야 한다는 것이었고 애초에 백엔드와 해당 글을 보면서 3000번 PORT로 맞추기로 협의하에 진행했다.
    • REDIRECT URI는 http://localhost:3000/users/signin/kakao로 등록까지 마쳤다.
  • 그리고나서 REST API키값을 기존에는 코드에 반영해놨다가 민감한 정보는 노출되면 안돼기 때문에 숨겨야 한다는 말을 들었고 환경변수를 활용하면 된다는 말을 들었다.

    • .env파일을 만들어 그 안에 보안상 노출되면 안돼는 값들을 저장하고 나중에 그 값을 활용할 때는 process.env.[변수명]이런식으로 활용하면 됐다.
    • 혹시 몰라서 REDIRECT_URI까지 그냥 같이 넣었다...
      .env파일에 명시된 REST_API_KEY값
      REACT_APP_REST_API_KEY=카카오에서 받은 KEY값
       REACT_APP_REDIRECT_URI=http://localhost:3000/users/signin/kakao
    • .env를 작성하고 .gitignore에 .env파일을 추가해 작업 후 푸쉬되지 않게 방지했다.
  • .env에 명시된 값들은 OAuth.js라는 파일을 만들어 인가코드를 받기 위해 사용했다.

    const REST_API_KEY = process.env.REACT_APP_REST_API_KEY;
    const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI;
    
    export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;
    • 이렇게 OAuth.js에서 KAKAO_AUTH_URL을 export시켜 Login.js에서 goToKakao라는 함수에 적용을 시켰다.

      const goToKakao = () => {
        window.open(KAKAO_AUTH_URL, '_self');
      };
    • 소셜로그인 버튼을 클릭하게되면 해당 함수가 실행되면서 인가코드를 받기위한 URL로 넘어가지는 과정이다.
      저 URL로 넘어가짐과 동시에 브라우저 URL창에 인가코드가 찍히게 되는데 그때 code라는 변수에 인가코드를 담아 백엔드에게 전달해주는 코드를 구성했다.

      const KakaoLoading = () => {
        const navigate = useNavigate();
        const location = useLocation();
        // location.search를 활용해 뽑아와야할 code값을 찾는다.
        // 그리고 qs를 활용해 값을 뽑아낸다.
        const code = qs.parse(location.search, {
          ignoreQueryPrefix: true,
        }).code;
      
        useEffect(() => {
          // 받아온 code값을 백엔드 주소로 body에 실어서 보내준다.
          axios.post(API.KAKAO_LOGIN, { code }).then(res => {
            // 백엔드와 소통이 성공해서 오는 토큰값을 로컬스토리지에 저장
            localStorage.setItem('token', res.data.token);
            // 토큰을 로컬스토리지에 저장함과 동시에 메인페이지 이동
            // 실패할 경우에는 catch를 사용하지 않고 조건부로 alert창을 띄우게 구성
            res.data.token ? navigate('/') : alert('로그인에 실패하였습니다.');
          });
        }, []);
        // 해당과정이 카카오 서버와 백엔드 서버간의 통신이 주요이다 보니 
        // 시간이 있어서 Loading이라는 컴포넌트를 만들어서 로딩화면 제작
        return <Loading />;
      };
      // 로딩화면 제작
      // 로딩화면이 필요한 곳에서 활용하도록 components폴더에 제작
      import React from 'react';
      import styled, { keyframes } from 'styled-components';
      
      const Loading = () => {
        return (
          <LoadingWrapper>
            <LoadingText>로딩 중</LoadingText>
            <Dot delay="0s" />
            <Dot delay="0.1s" />
            <Dot delay="0.2s" />
          </LoadingWrapper>
        );
      };
      
      const BounceAnimation = keyframes`
        0% {
          margin-bottom: 0;
        }
      
        50% {
          margin-bottom: 1rem;
        }
      
        100% {
          margin-bottom: 0;
        }
      `;
      
      const LoadingWrapper = styled.div`
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        right: 47%;
        top: 45%;
      `;
      
      const LoadingText = styled.h3`
        color: #568a35;
      `;
      
      const Dot = styled.div`
        background-color: #568a35;
        border-radius: 50%;
        width: 0.75rem;
        height: 0.75rem;
        margin: 0 0.25rem;
        animation: ${BounceAnimation} 0.5s linear infinite;
        animation-delay: ${props => props.delay};
      `;
      
      export default Loading;
  • 위의 과정을 거치고 성공적으로 통신이 완료됐다면 메인페이지로 넘어가짐과 동시에 Nav가 로컬스토리지에 토큰값을 확인후에 있다면 해당 유저의 정보(이름)을 띄운다.


2. 구현 간 Blocker

  • Nav와 Footer에서는 솔직히 스타일과의 전쟁이였을 뿐 Blocker라고 할 만한 부분은 전혀 없었다.

2-2. Login

  • 기존에 지속적으로 프로젝트하면서 로그인과 회원가입 기능은 몇번씩 해봤었지만 소셜로그인 즉, 외부 API를 활용해서 로그인을 시도해본다는 점은 매우 신선하면서도 신나면서도 두려웠다.
    상당히 어려울 것만 같고 이걸 어떻게 해야하나 걱정이 태산이었다.
  • 하지만 백엔드 팀원과 로그인 기능구현에 대해서 서로 회의를 하면서 역할 분담을 딱 하고 나니 매우 안심이 되었다.
  • a태그를 사용해서 환경변수에 숨겨둔 REST API 키 값이 그대로 브라우저에 노출되는 상황이 있었다.

3. Blocker 해결과정

3-2. Login

  • REST API를 기존에는 js파일에 변수로 담아서 바로 활용하다가 어느 순간 다른 팀원들이 해당 키값은 보안상 노출되면 안돼기 때문에 숨겨야 한다는 말을 들었다.
  • 그래서 환경변수(.env)에 담아서 .gitignore에 해당파일이 푸쉬되지 않게 방지하고 바로 적용해본 결과 로그인 버튼에 마우스가 올라가는 순간 a태그의 특성상 브라우저 좌측 하단에 명시해준 href주소가 그대로 노출되는 것이었다.
  • 이를 해결하고자 처음에는 useNavigate를 활용했다.
    import { useNavigate } from 'react-router-dom';
    import { KAKAO_AUTH_URL } from '../../OAuth';
    
    /* ... */      
    
    const navigate = useNavigate();
    const goToKakao = () => {
      navigate(KAKAO_AUTH_URL);
    }
    
    /* ... */
    
    // 기존에 a태그를 사용하지 않고 button으로 변경
    <LoginButton
      onClick={() => {
        goToKakao();
        }}
     >
       <KakaoLoginImg
         src="/images/Login/kakaoLoginButton.png"
         alt="loginBtn"
       />
    <LoginButton />
  • useNavigate를 활용해보니 useNavigate는 라우터의 기능으로 Path를 지정하고 이동하게끔 해주는 기능을 하다보니 우리가 필요한 HOST URL은 변경이 불가능 한 것이다.
  • 그러다보니 http://localhost:3000/https://...... 이런 형식으로 URL이 바뀌어 코드를 못받아오는 상황에 쳐했다.
  • a태그에 마우스가 올라갔을 때 url이 뜨는 것을 막기위해 사이트를 뒤져봤는데 해당 특성 자체를 바꿀 수 있는 것은 불가능하다고 한다.
    • 재미있던 점은 스택오버플로우에 이 문제와 동일한 질문이 올라와 있었는데 답변이 마우스가 올라갔을 때 떠오르는 url과 똑같은 색을가진 div를 만들어서 가리라는 것이었다.
      처음엔 놀리는 건 줄 알았는데 방법이 없다는 점때문에 저렇게 얘기했나 싶어서 그러려니 하며 넘어갔다....
  • 로그인 기능을 구현하는 다른 팀원들과 소통을 하면서 알아본 결과 window를 사용하면 가능하다는 것이었다.
      import { KAKAO_AUTH_URL } from '../../OAuth';
      
      /* ... */      
      
      // navigate만 빼고 그 자리를 window.open으로 변경
      // '_self'는 새로운 탭으로 열리지 않고 현재탭에서 이어 가는 역할을 해줌
      const goToKakao = () => {
        window.open(KAKAO_AUTH_URL, '_self');
      }
      
      /* ... */
      
      <LoginButton
        onClick={() => {
          goToKakao();
          }}
       >
         <KakaoLoginImg
           src="/images/Login/kakaoLoginButton.png"
           alt="loginBtn"
         />
      <LoginButton />
  • 이렇게 하고 나니 마우스를 올렸을때 주소도 안뜨고 코드를 받는 URL로 잘 넘어가지면서 보안성과 구현 문제를 동시에 해결했다.

4. 느낀점

4-1. 기존보다 확실히 성장했음을 많이 느낌(하지만 아직 갈 길은 멀다)

  • 예전에는 모르는게 생기면 생각하기 보다는 무조건 검색부터 하거나 아니면 주변 동료들에게 도움을 얻어 해답을 얻어가기만 했었다면
    이제는 내 스스로 먼저 의문점에 대해 하나씩 접근을 해가면서 Logic을 구성해본다.
  • 그리고 내가 맡은 기능을 끝내는데 예상외로 시간이 오래걸릴 줄 알았던 부분이 일찍끝나 다른팀원들을 도와주면서 방법을 바로바로 얘기할 수 있을정도의 수준이 얼추 올라왔다.(아직 많이 모자르지만 과거 1달전에 비해선 나아졌다.)

4-2. 그래도 아직 미숙한 협업툴 사용

  • 1차 프로젝트 종료 후 회고를 작성할 때 협업툴을 사용하는데 있어 많이 미숙하다고 했는데 2차 프로젝트때도 마찬가지였다.
  • 아예 사용을 하지 않은 것은 아니지만 확실히 아직까지도 직접 수기로 작성하는 부분이 편하다....
  • 그래도 점점 어떻게 활용해야 할지 익숙해지는 부분도 많았다 특히 Trello에서 백엔드와 같이 API소통 하면서 같이 해야 할 작업이 있을때 Common부분으로 누가누가 해야하는지 초대되어서 같이 해나갈때 편하다고 느꼈다.

4-3. 새로운 기술이나 닥치는 어려움에 있어 쫄지않고 해나가는 도전 정신이 향상

  • 예전에는 git하나만 명령어 새로운거 배워도 땀 흘리면서 했는데 지금은 add, commit, push는 당연하고 merge, branch -d, fetch, rebase, conflict등 수많은 상황이와도 무서워하지 않고 차근차근 해나가고 있다.
  • 또한, git에 대해 주변 동료들이 문제가 발생했다고 했을 때 자연스럽게 도와주다보니 내 자신도 천천히 성장함을 확실히 느꼈다.
  • git 뿐만 아닌 React의 다양한 외부 라이브러리도 마찬가지로 공식문서와 블로그에서 사용법을 참조해서 활용이 가능해졌다!!

5. 결론

1️⃣ 성장했지만 그것에 도취되어 자만하지마라 그러다 훅간다.
2️⃣ 소통은 언제나 중요한 것! 프론트엔드든 백엔드든 사람과 함께라면 대화를 는 것이 중요하다!
3️⃣ 1차 프로젝트 때와 마찬가지로 모든 답은 가까이 있으며 내가 설명을 많이 한다해서 많이 아는게 아니다. 지금보다 더 월등하게 노력해야한다!!
4️⃣ 누군가를 도와주는것은 나에게도 좋은것이다. 도움이 필요한 사람에겐 망설임 없이 도와주자!(도와주면서 나도 많이 배우고 공부하게 되었음!)
5️⃣ 어쩌다 PM을 1차에 이어 2차에도 맡게 되었는데 믿고 따라와준 팀에게 진심으로 감사드리고 같은 팀이어서 행복했고 영광이었습니다!! ☺️

profile
하나부터 열까지, 머리부터 발 끝까지

0개의 댓글