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
Problem 1 & Solution 1- 카카오 연동 로그인
- 카카오 개발자 사이트에서 어플리케이션 추가 및 정보입력
- 앱 키 발급
- 플랫폼 정보 등록
- Redirect URI 등록
: 로그인 요청을 했을 경우 발급되는 인가코드(Authorization Code)를 미리 등록된 Redirect URI에 전달됨
- 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>
- 해당 컴포넌트에서, Window 객체의 카카오 API 가져오기
const { Kakao } = window;
- 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차로 넘기고 마무리 하지 않은 기능이었음
- 파일 첨부 및 미리보기 기능 구현 로직
- 사진 첨부되는 Input 태그의 onChange에 첨부된 이미지 파일을 가져오는 함수 연결
: 첨부가 되면, e.target.files[0]으로 첨부된 이미지를 가져옴- 미리보기를 위한 조건부 랜더링 img 태그의 src 주소의 값으로 변환하기 위하여, FildReader()객체를 생성
- readAsDataURL method를 통해 변환
- 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번에서 연결된 함수 내에서 추가 내용 구현 삽입
- 할당된 이미지를 formData객체 생성 후 .append를 통해 연결하기
- 완성된 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
- Link로 state 전달
: 아래와 같이 state 키에 담아 전달 가능하고, 받는 쪽에서는 props.location.state.imgUrl 식으로 접근 가능
- 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과 연결 간소화
:
input
을label
로 감싸주면,htmlFor
나id
로 연결할 필요가 없음
기타 알게된 내용 - 천의 자리 마다 콤마 찍는 간단한 방법
:
toLacaleString
method 이용<p className="price">{Number(price).toLocaleString()}원</p>
메인화면(키워드 검색 & 필터)
상세페이지 및 리뷰 업로드
로그인 및 회원가입(카카오 소셜 로그인)
class 미리 보기(비디오 시청화면)
마이페이지
크리에이터 신청