'CLASS404' 프로젝트

mementomori·2021년 3월 4일
1

프로젝트 회고

목록 보기
2/3
post-thumbnail

프로젝트 개요

1. (클로닝) 프로젝트 사이트 : 'CLASS101'

: CLASS101은 온라인 강의 플랫폼 사이트

2. 팀 구성: 프론트 3명/ 백엔드 4명

3. 프로젝트 기간: 3/2 ~ 3/12

4. 프로젝트 진행 방식

: Agile(Scrum) 방식, Sprint 주기는 1주일
: 활용 Tool은 notion, trello, slack
: 매일 오전 11시 daily stand up meeting & sprint 주기 별로 정리 미팅(회고)

5. 화면 별 업무분담

: 찜하기(로그인 권한 없는 액션) 시도 -> 로그인/회원가입(소셜로그인) -> 상세페이지(리뷰업로드, 비디오 미리보기) -> 찜하기 -> 크리에이터 신청 -> 마이페이지(프로필 사진 교체 포함) 확인 Flow 중심
: 내가 담당한 부분은 (1), (3), (4), (5) + 페이지 최종 취합
* (1) 로그인/회원가입 - 카카오 연동 로그인, validation
(2) 메인화면 (클래스 목록 display) - 키워드 검색, 조건 검색 기능
* (3) 상세 페이지
* (4) 리뷰 업로드 페이지 - 사진 미리보기, 이미지 파일 전달
* (5) 비디오 시청 페이지 - 영상 시점 이동
(6) 마이페이지 - 장바구니 기능, 프로필 이미지 교체
(7) 크리에이터 신청 페이지
(8) Nav
(9) Footer

6. 기술 스택

  • Front-End : React.js, Sass(Scss), React-router-dom, React Hooks, Styled - - Component
  • Back-End : Python, Django web framework, Bcrypt, My SQL
  • 협업에 사용 된 툴 : Git Hub, Notion, Slack, Trello, Google Calender
  • Common : RESTful API

Problems & Solutions

Problem 1 & Solution 1- 카카오 연동 로그인

  1. 카카오 개발자 사이트에서 어플리케이션 추가 및 정보입력
  2. 앱 키 발급
  3. 플랫폼 정보 등록
  4. Redirect URI 등록
    : 로그인 요청을 했을 경우 발급되는 인가코드(Authorization Code)를 미리 등록된 Redirect URI에 전달됨
  5. index.html파일에서 JavaScript SDK 적용(다운로드) 및 SDK 초기화
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap"
      rel="stylesheet"
    />
    <script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
    <script>
      Kakao.init("앱키");
      // console.log(Kakao.isInitialized());
    </script>
    <link rel="icon" href="./favicon.png" />
    <title>클래스404</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
  1. 해당 컴포넌트에서, Window 객체의 카카오 API 가져오기
    const { Kakao } = window;
  2. Kakao.Auth.login() 함수를 통해, 로그인 팝업창 띄우고, 로그인 처리
    :로그인 버튼에 onClick으로 연결되어 있는 함수내에서 Kakao.Auth.login() 실행
    :success 콜백함수를 통해 카카오 사용자 토큰을 받을 수 있음
    :로그인에 성공 후에는 전달 받은 카카오 토큰을 서비스 백엔스 서버에 보내고, 자체 토큰을 다시 전달 받아 localStorage에 저장
const kakaoLogin = (e) => {
    e.preventDefault();
    Kakao.Auth.login({
      success: function (authObj) {
        console.log('kakao', authObj);
        fetch(`${KAKAO_API}`, {
          headers: {
            Authorization: authObj.access_token,
          },
        })
          .then((res) => res.json())
          .then((res) => {
            localStorage.setItem('kakao_token', res.access_token);
            localStorage.setItem('profileImage', res.profileImage);
            localStorage.setItem('user_name', res.user_name);
            if (res.access_token) {
              alert('로그인 성공!');
              props.history.push('/');
            }
          });
      },
      fail: function (err) {
        alert('로그인 실패!');
        console.log('err', err);
      },
    });
  };

Problem 2 & Solution 2 - 이미지 파일 첨부, 미리보기, 전송(FormData)

: 리뷰 업로드 기능을 구현 중, 1차 프로젝트에서 구현하다가 2차로 넘기고 마무리 하지 않은 기능이었음

  • 파일 첨부 및 미리보기 기능 구현 로직
  1. 사진 첨부되는 Input 태그의 onChange에 첨부된 이미지 파일을 가져오는 함수 연결
    : 첨부가 되면, e.target.files[0]으로 첨부된 이미지를 가져옴
  2. 미리보기를 위한 조건부 랜더링 img 태그의 src 주소의 값으로 변환하기 위하여, FildReader()객체를 생성
  3. readAsDataURL method를 통해 변환
  4. 3번 method가 완료되면 자동으로 호출되는 onlaodend method를 만들고, result 값을 받아 위의 src 주소에 연결
let reader = new FileReader();
    reader.readAsDataURL(img);
    reader.onloadend = (e) => {
      const base = e.target.result;
      setImgUrl(base);
    };
  • 파일 전송(FormData) 구현 로직
  1. 첨부 및 미리보기 로직, 1번에서 연결된 함수 내에서 추가 내용 구현 삽입
  2. 할당된 이미지를 formData객체 생성 후 .append를 통해 연결하기
  3. 완성된 formData를 body에 담고, header에 'content-type':'multipart/form-data' 로 설정하여 백엔드에 Request 송신

Problem 3 - 유동적 Query String 생성

: 2 이상의 검색필터 조건을 유동적으로 query string으로 만들어 백엔드에 보내고자 했으나, 웹 주소 창에 찍히는 path와 시차가 발생하고, 어떤 필터를 먼저 선택하고, 이후 삭제하는 지에 따라 오류가 발생하였음

Solution 3

Problem 4 - Route를 이용한 컴포넌트 간 데이터(state) 전달

: Link와 history.push로 페이지 이동을 하면서, 이동하는 컴포넌트에 id와 같은 데이터를 전달해주어야 하는 상황이 있었음 (예를 들어, 로그인 후 이동하는 페이지에서의 nav UI 반영하고자 하는 경우)

Solution 4

  1. Link로 state 전달
    : 아래와 같이 state 키에 담아 전달 가능하고, 받는 쪽에서는 props.location.state.imgUrl 식으로 접근 가능
  2. history.push 이동시 state 전달
    : 아래와 같이 state 키에 담아 전달 가능하고, 받는 쪽에서는 props.location.state.imgUrl 식으로 접근 가능
history.push({
  pathname: "/set_account",
  state: {userCell: userCell}
})

참고 링크: https://velog.io/@dhlee91/this.props.history.push%EB%A1%9C-props-%EB%84%98%EA%B2%A8%EC%A3%BC%EA%B8%B0
https://medium.com/@ghur2002/react-router%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-component%EA%B0%84%EC%97%90-props-%EB%84%98%EA%B2%A8%EC%A3%BC%EA%B8%B0-610de3511c67

기타 알게된 내용 - Styled Comoponent 사용법

: 동일 유사 스타일을 반복적으로 사용되는 경우, 한 컴포넌트에서 export하고 다른 컴포넌트에서 import로 전달받고, styled(styled Component명)을 입력하여 사용가능

기타 알게된 내용 - Object Mapping

: 여러 input elements로부터 각각 다른 입력 값(e.target.valeu)를 전달받아 setState하고자 하는 경우, 객체매핑을 통해 간략하게 표현가능

const SET = {
    email: setEmail,
    password: setPw,
    repassword: setRePw,
    name: setName,
  };
  const handleInput = (e) => {
    const setState = SET[e.target.id];
    setState(e.target.value);
  };

기타 알게된 내용 - input을 label과 연결 간소화

: inputlabel로 감싸주면, htmlForid로 연결할 필요가 없음

기타 알게된 내용 - 천의 자리 마다 콤마 찍는 간단한 방법

: toLacaleString method 이용

<p className="price">{Number(price).toLocaleString()}원</p>

최종 완성

  • 메인화면(키워드 검색 & 필터)

  • 상세페이지 및 리뷰 업로드

  • 로그인 및 회원가입(카카오 소셜 로그인)

  • class 미리 보기(비디오 시청화면)

  • 마이페이지

  • 크리에이터 신청

느낀 점(회고)

이전 배운 기술보다는 새로운 기술에 대한 연습을 위해, Styled Component와 Hooks를 적극 사용했는데, 예상했던 것 보다는 기본적인 사용법이 많이 어렵지않아 쉽게 적용해볼 수 있었음.

첫 프로젝트에 비해서는 기능 구현 자체에 대한 어려움은 상대적으로 크지 않았지만, React의 작동원리나 로직을 정확하게 이해하지는 못하고 있어, 컴포넌트 설계나 데이터 흐름에 대한 효율적 설계가 부족한 것 같다고 생각했음. (상황에 따라 오류 발생)

이번에 두 번째로 경험한 Agile(Scrum) 방식의 협업 혹은 프로젝트 진행방법은 개인적으로 굉장히 인상적인 경험이었음

1차 프로젝트에 비하여, 백엔드와의 협업에서 사전에 고려할 점에 대한 명확한 이해가 있었으며, 이를 고려하여 mock data 설계를 하여 사후 조율이 수월하였음

git flow(Rebase)등 더 유용한 git 명령어와 기능들에 대해 배울 수 있었던 시간이었음

setState는 비동기 함수이기 때문에, 하나의 함수 안에서 setState와 동시에 update된 state 값을 꺼내쓰지 않도록 유의해야함! => update 후 실행이 보장되는 class component에서 setState함수의 2번째 인자의 콜백함수로 실행 하거나, lifecycle method 활용할 것!

profile
21c Carpenter

0개의 댓글