OTHERS/내 생각

공통 프로젝트를 돌아보며

sinawi95 2021. 8. 21. 21:15
728x90

저의 입장에서 기술하는 공통 프로젝트 내용입니다. 소스코드는 gitlab에 있는데 반출이 어려워 회고 느낌으로만 적어봅니다

프로젝트

  1. 주제: 대화형 레시피 웹 앱

  2. 기획

    • 결정된 내용
      1. 우리 서비스가 왜 필요한가?
        • 손에 가루나 양념같은게 묻어있는 경우 모바일 화면 등을 만지기 쉽지 않다.
        • 대화하듯이 말하면서 요리에만 집중할수 있게 한다.
      2. 무엇을 만들어야할까?
        • 핵심 기능: 말로 요청하면, 조작도 가능하고, 음성으로 응답도 해주는 대화형 레시피 웹앱
        • 구글이나 네이버 등의 AI 음성인식 서비스를 사용해서 내가 하는 말을 듣고 이해함
        • 레시피는 TTS로 읽어줌
  3. 설계

    • WireFrame

      • 최종 결과물(첫 설계와 비교하기 위함)
        1. 메인페이지
          1. 최근 올라온 메뉴
        2. 사이드바
          1. 로그인/마이페이지
          2. 레시피 선택(둘러보기(전체), 레시피 고르기(분류))
          3. 커뮤니티
        3. 로그인/회원가입
          1. 소셜로그인만 구현
        4. 마이페이지
          1. 인증한 글
          2. 평가한 레시피
          3. 스크랩한 레시피
        5. 요리(레시피) 검색
          1. 분류(레시피 고르기)
            1. 나라별
            2. 테마별
              1. 시간
          2. 레시피 선택(둘러보기)
            1. 구글 이미지 검색 느낌: 이미지 선택하면 상세페이지가 오른쪽으로 나오게
            2. 이미지 사진, 재료, 시간, 후기, 평점 등
        6. 요리(레시피) 상세글
          1. STT - WEB SPEECH API
          2. 타이머
        7. 커뮤니티: SNS 기능
          1. 핀터레스트 느낌
    • Component

      • 최종 결과물(첫 설계와 비교하기 위함)

        FRONTEND
        /src
        ├ /components: 각 페이지를 구성하는 컴포넌트
        │ ├ /user : login, signup, mypage
        │ ├ /recipe : 레시피 관련 모든것
        │ ├ /community : 커뮤니티(피드) 관련 모든것
        │ └ /common : 여러 페이지에서 사용될 만한 것
        ├ /lib: redux에서 사용하는 라이브러리
        │ └ /api: 비동기 처리 함수()
        ├ /redux: 상태관리
        │ └ / modules: 상태관리에서 쓰이는 함수(액션,리듀서)
        ├ /style: 컴포넌트 디자인
        ├ index.js: 최상위 페이지, redux store 
        ├ Routes.js: react route 관련
        └ App.js: index, routes 사이
        • 처음엔 전역 상태 관리가 필요없을 줄 알고 react만 사용함
        • 로그인 상태 유지를 위해 redux가 필요한 것을 느꼈고 redux와 관련된 디렉토리를 생성함
  4. 구현

    • 사용 기술

      React + Redux

      Web Speech API

      AWS S3

    • 주차/일자 별 내용/ 느낀점

      • 1주차(0712~0718)

        • 웹 디자인이라 프론트에 조금 더 특화되어있다고 느꼈다.
        • 첫 과제부터 UX와 UI에 대한 이해였기 때문이다.
        • vue 스켈레톤 코드를 따라가고 있었지만 기획할 때 명세서를 사용하지 않기로 해서 그대로 버렸다.
        • 모종의 사유로 인해 스켈레톤 코드와 명세서를 안보고 직접 기획해서 구현하기로 했다.
        • 그래서 첫 주는 Git, Jira 익숙해지는걸 목표로하였다.
        • 최종적으로 제출한 프로젝트에 1주 차에 기여한 내용
          1. 아이템 기획(여러 아이템 중 하나 선정)
          2. Git, Jira 사용법 익히기
      • 2주차(0719~0725)

        • 프로젝트 주제 결정(대화형 레시피 웹 앱, 핵심기능 선정)
        • React Native 공부 → 나중에 react로 한번더 바뀜
        • 명세 최종 확정후 기술 스택 공부
        • flowchart, wireframe, erd 작성
        • 최종적으로 제출한 프로젝트에 2주 차에 기여한 내용
          1. 아이템 기획(경쟁사분석, 차별점, 요구사항 구체화 등) 및 최종확정
          2. 기술스택 선정 및 환경 설정
          3. Flow chart: 요구사항 보고 작성
          4. Wireframe: 플로우 차트를 보고 기본적인 UI 작성
      • 3주차(0726~0801)

        • 적어도 3주차 까지는 기본기능을 만들어야 한다고 생각하였다.

          • 4주차부터는 핵심기능이랑 컨텐츠, 디자인에 많이 신경을 써야해서 기본기능도 안되어있으면 더힘들어질거라 생각했다.
        • React Native에서 React로 변경했다.

          • 하단 "어려운 점"에 상세히 기술
        • 메인페이지

          • 레이아웃은 팀원과 같이 제작하였다. 가장 기본이 되는 페이지이고 리액트를 처음 써보는 단계여서 익힐겸 같이 제작하였다.
          • 버튼을 눌렀을때 사이드바가 나오는 app bar(navbar)를 두었다.
          • 추천 요리와과 테마별 요리 추천에 들어갈 컴포넌트를 작성했다.
          • 카드와 카로셀은 자주 쓰일거 같으므로 /src/common 에 작성하기로 했다.
          • 카로셀은 생각보다 안되는게 많아서 나중에 하기로 하고 크기만 잡아놓았다.
          • Material ui 사용하면서 애를 많이 먹었다.
          • bootstrap이 조금더 익숙하기도 하고 반응형 만들때나 마진등을 넣을때 조금더 편하다고 느낌
        • 로그인 개발

          • 여기서부터 기능을 나누어서 개발하였다.
          • 팀원분은 레시피 관련된 페이지를 만들기로 했다.
          • 로그인은 소셜로그인 여러개를 필요로 해서 누를수 있는 페이지를 만들었다.
          • 카카오 로그인을 프론트만 개발했다.
          • 자세한건 "어려운점"에 기술
        • 커뮤니티 개발

          • 요리가 끝난 이후 인증할수 있는 페이지를 생성했다.(article CRUD 중 Create)

          • 저장 폼은 만들었으나 이미지 저장을 어떻게 구현할지 고민이 되었다.(4주차에 개발)

            • 프론트에서 이미지 서버로 직접 올리는 방식이 좋은지 백엔드서버에서 이미지서버로 올리는 방식이 좋은지는 모르겠다.

            • 이미지 저장에서 선택할수 있는 사항은 세가지 였다.

            • 백엔드 서버에 직접 저장하는 방식:

              구현은 쉽긴하지만 레시피 영상이나 저장될 이미지들이 많아서 분리하는게 더 낫다고 생각했다.

            • 백엔드 서버로 이미지를 같이 보내고, 백엔드에서 이미지 서버에 저장하는 방식

              이 방식이 보안에도 좋을거같다고 생각했지만 그만큼 백엔드 서버에 요청하는게 많아져서 속도가 느려질거같았다.

            • 프론트에서 이미지 서버에 직접 저장하는 방식:

              이미지 서버에 직접 저장하고 받은 주소를 백엔드로 보내는 방식이다.

              이 방식을 사용하기로 했는데 그 이유는 레시피를 받아오는 요청이 많아서 이미지 까지 담당하면 많이 느려질거라 판단했고, 백엔드 담당하는 분들이 너무 바빠보이기도 했기 떄문이다.

            • 사진 업로드는 로그인한 사람만 접근할수 있게 하였는데 백엔드 서버와 이미지 서버를 따로 구현하는게 맞는거같긴하다.

          • 사진 업로드

            • 사진 선택 버튼 디자인
              • 원래의 input 태그를 hidden으로 바꿔서 안보이게 하고 ref를 설정한다.
              • 버튼을 새로 만들어 디자인하고 눌렀을때 해당 ref를 클릭하는 이벤트를 설정한다.
            • 사진 업로드할때 모바일에선 카메라로 접근할수 있게 만들었다.
              • input 태그에 capture='camera' 를 추가하면 된다.
            • 이미지 미리보기 기능을 만들었다.
              • useState를 사용하여 selectedFile가 있으면 보여주었다.
          • 커뮤니티는 사진이 들어가야하므로 핀터레스트 형식으로 구현했다.

        • 리액트 라우터로 주소 요청에 따라 페이지 전환을 구현했다.

        • 환경변수

          .env 파일을 사용하였다.

          • 백엔드 서버에 요청을 보내는 주소와 포트를 적어두었다.
          • 여러 군데에서 사용하기도 하고 하드코딩으로 직접 노출하는 것보단 나을 것이라 판단하였다.
          • 추후에 다른 api key를 사용할때 어차피 사용해야해서 미리 적용했다.
          • 리액트에선 기본적으로 dotenv가 설치되어있지만 REACT_APP을 붙인 변수명을 사용해야 읽을수 있었다. process.env.REACT_APP_API_URL
        • 최종적으로 제출한 프로젝트에 3주 차에 기여한 내용

          1. 기본적인 기능을 제작하고 ui 틀을 다짐
          2. 환경변수 파일 작성
          3. 카카오 로그인
          4. 커뮤니티 인증 게시글 업로드 기능 개발
      • 4주차(0802~0808)

        • 남은 기본 기능들을 빠르게 만들고 STT에 힘을 쏟고 싶었지만, redux를 적용하게 되면서 STT는 뒤로 미루게 됨

        • 커뮤니티 개발

          • 커뮤니티 인증 글 상세페이지(Read), 수정(Update), 삭제(Delete) 개발
            • 수정할땐 기본 create 폼을 재사용하는 방식으로 개발하였다.
          • 로그인 상태를 저장해야함을 느꼈다. → redux를 적용하게 된 계기
          • 모든 인증글을 조회하여 핀터레스트 형식(masonry style)으로 보여주었다.
            • 딱 하나 있을때 카드가 분리되는 문제가 발생하였다.
            • 직접 작성했던 masonry 관련 css를 모두 확인해봤지만 고칠수 없어서 material ui 의 card 컴포넌트와 충돌이 나는 것으로 판단하였다.
            • 새로운 패키지를 사용해서 해결하였다.
        • Redux 적용

          • 로그인이 된 상태인지 확인해야하는 경우가많았기 때문에 상태관리의 필요성을 느꼈다.

          • 처음부터 리덕스를 쓰고있지 않았기 때문에 이때까지 작성한 것들에 대해서는 그대로 쓰고 필요한 경우에만 리덕스를 적용하기로 팀원과 합의했다.

          • 리덕스를 처음 사용할때 공식 문서를 봐도 엄청 이해가 안되어서 시간을 많이 버렸다.

          • 참고글에 있는 블로그를 보면서 왜 사용해야하는지 등을 대충 익히고 이메일 로그인, 이메일 회원가입을 리덕스로 구현하면서 익혔다.

          • 스토어도 읽히고 값도 받아올수 있는데 dispatch가 안되는 문제가 있었다. 거짓말 안하고 어디가 안되는지 하나하나 찾았는데 오타문제 였다. (이거때문에 하루 날렸다.)

          • 리덕스를 사용할때 Ducks pattern이라고 하는 디자인패턴을 적용했다.

            • 한 파일에 액션, 리듀서를 같이 작성하는 패턴
          • 참고글

            https://velog.io/@youthfulhps/What-is-Redux-and-why-use-it
            https://velog.io/@velopert/
            https://velopert.com/3533
            https://backend-intro.vlpt.us/6/01.html
            https://ko.redux.js.org/introduction/getting-started/
            https://redux.js.org/

        • 주소를 통한 접속 일부 차단

          • 요리 인증글(article create)과 같이 음식의 아이디가 필요한경우 이전 페이지에서 history.push로 파라미터를 같이 넘겨주는 방식으로 구현하였다..
          • 주소를 통해 들어가게되면 넘겨주는 값이 null 이되므로 잘못된 접근 방식이라고 경고창을 띄우고 메인 페이지로 돌아가게 만들었다.
        • STT 비교 및 선택

          Web Speech API와 react-player를 사용하여 제어해보았다.(거의 체험수준)

        • 최종적으로 제출한 프로젝트에 4주 차에 기여한 내용

          1. 카카오 소셜 로그인
          2. Redux 적용
          3. 커뮤니티
      • 5주차(0809~0815)

        • STT 비교 및 선택

          1. web speech api

            장점: 브라우저 내에서 사용 가능

            단점: 못알아듣는 단어가 조금 있음(발음 문제인지는 모르겠음)

          2. teachable machine(teachablemachine.withgoogle.com/train/audio)

            장점: 학습 데이터가 많을 수록 정확도 높아짐. 브라우저 내에서 사용 가능(tensorflow.js)

            단점: 학습 데이터가 많을 수록 정확도 높아짐. 인식 속도가 가변적임(빨랐다 느렸다 함)

            • 학습 데이터가 많으면 정확도가 높아지는게 좋았지만 그 데이터를 만드는 시간이 오래 걸릴 거 같았다.
          3. 카카오

            장점: 한국어인식 잘한다고함

            단점: 아직 베타서비스. 실시간으로 적용하려면 백엔드에서 단어 단위로 끊는 작업이 필요.

            • 카카오 로그인이 구현되어있어서 활성화만 하면 사용할수 있을줄 알았다.
            • 스트리밍처럼 계속 켜있는건 못하고 파일을 보내서 음성인식 결과를 받는 방식이라 그 로직을 구현하는게 오래 걸릴거같아서 그만두었다.
          4. 구글

            장점: 한국어 인식 잘됨. 가이드 있음

            단점: 실시간으로 적용하려면 서버에서 작업이 필요.

            • 구글의 STT를 사용하는게 가장 성능이 확실하겠지만 적용하다가 6주차에도 못 만들거 같았다.
          • 그래서 간편히 사용할수 있는 Web Speech API 를 주장했고, 얘를 사용하기로하였다.
        • 레시피 제어

          • 레시피 단계를 보여주는 컴포넌트에 STT 컴포넌트를 넣을 수있게 만들었다.
            • 전체 서비스에서 사용할수도 있을거같아서 common 에 만들었다.
          • STT 컴포넌트에 Web Speech API를 만들고 마이크 on/off 표시와 현재 인식된 값을 표시하게 만들었다. → 나중에 디자인함
          • Web Speech API를 사용하여 Command에 맞게 제어했다.
            • Web Speech API가 변환한 값과 같은 command 값을 찾아 함수를 발생시킨다.
            • 이 방법을 사용해서 dispatch로 command 값을 변경했고 상위 컴포넌트(recipeStep)에서 command 값을 읽어서 제어했다.
            • 레시피 단계는 react-slick 에 있는 slider를 사용했는데 input을 사용해서 슬라이더 위치를 제어할수 있었다. command에 'next' 나 'previous' 가 들어오면 이 인풋값을 변경하는 것으로 제어했다.
            • 비디오는 slider내에 하나씩 들어있었기 때문에 #video{index} 로 id를 할당했고 queryselector를 사용하여 비디오 태그를 찍어 제어하였다.
            • 타이머 또한 비디오와 같은 방식을 사용하였으나 하위컴포넌트로 만들어졌기때문에 index값도 내려서 id를 할당했다. 이런 방식을 했을때 에러가 많이 떴는데 이는 아래 "어려운점"에 서술하겠다.
        • 이미지 업로드 S3 연동

          • 이미지를 저장하는 방법은 3주차에 고민했던것이었지만 S3를 사용해본적이 없기도 했고 백엔드와 같이 의논을 해야했던 것이어서 5주차에 만들게 되었다.
          • 백엔드 개발을 해주시는 분이 S3 버켓을 만들고 정책 등을 설정해서 사용할수 있게 되었다.
          • 사용되는 s3주소는 .env 파일에 저장해서 사용했다.
          • 이미지 저장을 하면 반환되는 값에 주소가 포함되어있어서 formdata에 보내는 imgurl 값을 교체해서 보내주었다.
        • 마이페이지

          • 유저 정보 관리 페이지: 카카오 로그인만 사용해서 버튼만 만들어놓고 disable 처리함
          • 아래 작성하는 모든 목록들에서 최근 5개의 글만 뜨게했다.
          • 작성한 인증 목록
            • 레시피 마지막에 나오는 글이자 커뮤니티 피드에 올라가는 글이다.
            • 기존의 카드 컴포넌트를 공유해서 사용하려 했으나 원하는 배치가 나오지 않아 새로운 카드 컴포넌트를 만들었다.
            • 레시피 평가를 일정 시간 이후에 푸쉬알림으로 보내주는걸 구현하려 하였으나 firebase나 PWA(progressive web app)등을 찾아본 결과 시간내로 못만들거라 생각해서 인증한 글에 대해서만 평가할수 있게 만들었다.
            • 마이페이지에서 작성한 인증목록으로 들어온 경우에 param을 보내서 true값인 경우에만 평가가 가능하게 만들었다. 주소를 직접 쳐서 들어온 경우에나 다른 컴포넌트에선 평가하기 버튼이 뜨지 않는다.
          • 작성한 평가 목록
            • 인증한 목록과 같은 카드 컴포넌트를 사용했다.
          • 스크랩한 레시피
            • 인증한 목록과 같은 카드 컴포넌트를 사용했다.
        • 타이머 개발

          • 타이머를 쉽게 개발할줄 알았지만 생각보다 꽤 오래걸렸던 작업이다.
          • useState를 사용해서 setInterval로 1초에 한번씩 값을 감소하는 방법이 있었는데 이 방법은 계속 렌더링을 하는 방법이라 계속 페이지가 바뀌었고 사용하기 어려웠다.
          • useRef를 사용해서 컴포넌트 안에 변수를 만드는 방법을 사용하여 해결했다.
          • 하지만 이 때도 문제가 발생했다. 슬라이더에서 한꺼번에 사용하는경우에 start, stop, reset버튼을 직접 눌렀을 경우엔 각각 제대로 작동했으나. 음성으로 제어할땐 start 되었으나 stop과 reset 버튼이 동작하지 않았다.
          • 음성으로 제어할땐 clearInterval이 제대로 작동되지 않았는데 모든 슬라이더의 start 버튼이 눌려 타이머가 진행되었기 때문이다. 그래서 video처럼 id값을 주고 제어하는 방식으로 해결하였다.
          • warning이 계속뜨긴했지만 원하는 대로 동작했고 타이머에만 시간을 너무 들일수없어서 그냥 넘어가기로 했다.
        • 최종적으로 제출한 프로젝트에 5주 차에 기여한 내용

          1. STT, 레시피 제어
          2. 마이페이지(인증글, 평가한 레시피, 스크랩 레시피)
          3. 타이머
      • 6주차(0816~0820)

        • 배포 서버에서 소셜 로그인

          • 진짜 골머리를 앓게 한 소셜 로그인이었다.
          • Redirect URI를 제대로 설정하자...
        • 디자인

          • 디자인이 가장 중요하지만 공대 테크를 탄 나에겐 가장 어려운 문제였다. 차라리 기능을 만들라하면 만들겠는데 이건 도저히...

          • 그래서 우선적으로 정렬만 한 상태로 만들었고 나중에 다른 분이 만들어둔 디자인을 따라가기로 했다.

        • 개발과 관련되지 않는 것

          • 자체 레시피 DB 등록
          • 레시피 영상 촬영
            • 아이폰 8과 맥북과 파이널컷.
            • 자막 다는것도 힘들었지만 어떻게든 만들었다.
            • 레시피 영상
        • 최종적으로 제출한 프로젝트에 6주 차에 기여한 내용

          1. 끝까지 말썽 부리던 카카오 소셜 로그인
          2. (영상 촬영, 레시피 영상, ucc에 들어가는 영상)
  5. 발표

    • 팀장님이 아이템 기획으로 이미 만들어서 발표한 자료가 있어서 그걸 토대로 만들었다.
    • 프로젝트 발표에서 가장 중요하다고 생각한게 기획 의도랑 핵심 기능이어서 서비스를 설명하기 전까지 어떻게 풀어가면 좋을지 많이 고민했다.
    • 뭔가 열심히는 준비했는데 꽤 부족하다고 느꼈다. 발표 당시에도 굉장히 허둥지둥하기도 했고 리허설에 했던거랑 내용이 조금씩 바뀌어서 제대로 못한거같다.
    • 발표할때 생각보다 많은 팀이 개발 스택을 써놓았고 구현한 기능을 하나하나 설명하는 식으로 발표했다. 발표 전까지만 해도 발표는 짧은 게 좋다고 생각해서 핵심 기능을 구체적으로 이야기하고 전체적인 기능은 흐름만 알 수 있게 했는데 긴 것도 나름 괜찮은거 같다. 아마 소스코드 반출이 어려우니 ppt나 발표 영상으로 대체하는 거 같다.

어려웠던 점

  1. 기획 3주

    1. 네 명이 모두 관심을 갖는 아이템을 선정하고 요구사항을 정하는게 정말 어려웠다.
    2. 조금이라도 관심 없는 분야인경우 프로젝트 개발때 흥미를 가지지 못할거 같아서 조금씩이라도 관심이 있는 분야로 선정했다.
    3. 기획 땐 아니지만 생각보다 의미없이 시간만 잡아먹는 회의가 많았던 거 같다. 분명 해결해야하는 문제인데 해결책이 없거나 대화에 진전이 없는 그런 회의들이 있었다.
  2. 리액트 네이티브로 개발하다가 리액트로 전환함

    1. 팀 미팅때 웹 서비스에 웹뷰를 사용하여 모바일 환경에서 사용할수 있는 걸 추천받았다.
    2. 모바일 환경이라는 단어에서 리액트 네이티브로 안드로이드, iOS 환경을 구축하고 거기에 Web에서 돌아갈수 있게 만들기로 하였다.
    3. 일주일 정도 개발하다가 어떻게 하다보니 프로젝트 관련 상담을 다시 받았고 웹 서버를 구축해야한다고 하였다.
      • 일차적으로 웹서버를 돌릴수 있는지에 대해서 컨설턴트님이 의문을 가졌다.
      • 앱으로 웹을 돌리는 거랑 웹으로 앱을 돌리는거에 대한 차이를 설명했으나 공통 프로젝트에서는 무조건 웹서버를 기반으로 만들어야한다고 했다.
      • 웹앱에 대한 이해가 부족했던것 같음
    4. 프로젝트가 다 끝나서 하는말이지만 리액트 네이티브로도 웹서버를 충분히 돌릴수 있을거 같다. 오히려 컴포넌트 관련해서는 디자인할때 더 편하게 할수 있지 않았을까 하는 생각이 살짝 든다. 물론 그랬을 경우엔 stt가 되었을지는 모르겠다.
  3. 리액트만 사용하다가 리덕스의 필요성을 느껴 중간에 추가함

    1. 처음부터 리덕스를 쓰고있지 않았기 때문에 이때까지 작성한 것들에 대해서는 그대로 쓰고 필요한 경우에만 리덕스를 적용하기로 팀원과 합의했다.
    2. 리덕스를 처음 사용할때 공식 문서를 봐도 엄청 이해가 안되어서 시간을 많이 버렸다.
    3. 참고글에 있는 블로그를 보면서 왜 사용해야하는지 등을 대충 익히고 이메일 로그인, 이메일 회원가입을 리덕스로 구현하면서 익혔다.
    4. 스토어도 읽히고 값도 받아올수 있는데 dispatch가 안되는 문제가 있었다. 거짓말 안하고 어디가 안되는지 하나하나 찾았는데 오타문제 였다. (이거때문에 하루 날렸다.)
    5. 리덕스를 사용할때 Ducks pattern이라고 하는 디자인패턴을 적용했다.
      • 한 파일에 액션, 리듀서를 같이 작성하는 패턴
  4. 상위 컴포넌트에서 하위컴포넌트 제어

    1. 레시피 단계에서 타이머를 제어할때 에러
    2. 음성인식으로 비디오를 제어할때 id값으로 비디오 태그를 찾아서 직접 제어하는 방식을 사용했다.
    3. 타이머도 이런 방식으로 사용했는데 비디오와 다르게 시뻘건 warning이 떴다.
    4. 상위컴포넌트 하위 컴포넌트를 변경하게 되면 렌더링이 안될수 있다는 경고였다.
    5. 그래서 상위에서 하위 컴포넌트의 함수를 사용하는 방법(forwardRef, useImperativeHandle) 등 여러 방법을 찾아봤다.
    6. 하지만 모두 에러가 지워지지 않고 원하는 대로 제어가 되지 않아서 쿼리셀렉터로 지정하는 방식을 사용하였다.
  5. 타이머 구현(4와 이어지는 내용)

    1. 타이머를 쉽게 개발할줄 알았지만 생각보다 꽤 오래걸렸던 작업이다.
    2. useState를 사용해서 setInterval로 1초에 한번씩 값을 감소하는 방법이 있었는데 이 방법은 계속 렌더링을 하는 방법이라 계속 페이지가 바뀌었고 사용하기 어려웠다.
    3. useRef를 사용해서 컴포넌트 안에 변수를 만드는 방법을 사용하여 해결했다.
    4. 하지만 이 때도 문제가 발생했다. 슬라이더에서 한꺼번에 사용하는경우에 start, stop, reset버튼을 직접 눌렀을 경우엔 각각 제대로 작동했으나. 음성으로 제어할땐 start 되었으나 stop과 reset 버튼이 동작하지 않았다.
    5. 음성으로 제어할땐 clearInterval이 제대로 작동되지 않았는데 모든 슬라이더의 start 버튼이 눌려 타이머가 진행되었기 때문이다. 그래서 video처럼 id값을 주고 제어하는 방식으로 해결하였다.
    6. warning이 계속뜨긴했지만 원하는 대로 동작했고 타이머에만 시간을 너무 들일수없어서 그냥 넘어가기로 했다.
  6. history push 할때 새로고침 안됨

    1. redux store는 새로고침하면 초기화되는 특성이 있는데 이를 사용해서 개발함.
    2. 하지만 push를 하면 새로고침이 되지 않아 이전 값들을 계속 사용하는 경우가 생김.
    3. 마이페이지와 커뮤니티 피드가 가장 큰 문제 였음.
    4. 마이페이지는 redux store에서 같은 저장소를 공유하면서 사용했는데 인증 목록, 평가목록, 스크랩 레시피를 보여주는 페이지에 들어갔다가 다시 마이페이지로 돌아가면 해당 목록을 그대로 보여주는 문제가 있었다.
    5. 같은 저장소를 사용하지 않고 분리해서 각각의 값을 저장하게 했다.
    6. 커뮤니티 피드는 삭제해도 이전값이 남는 문제가 있었다. 삭제하면 새로고침하면서 값을 가져와야하는데 새로고침이 되지 않아서 동작하지 않았다.
    7. useEffect() 에 [match.params.url] 을 넣어서 주소가 바뀔때마다 값을 가져오도록 만들어서 해결하였다.
  7. 카카오 소셜 로그인/로그아웃

    • 카카오 소셜 로그인은 사용자의 카카오 계정을 사용하여 토큰을 받아 로그인할수 있게 만드는 기능이고 OAuth 2.0 기반이다.

    • Kakao Developer에 애플리케이션 등록

      • 카카오 api를 사용하기 위해 필수이다.
      • 플랫폼에 사이트 도메인을 설정한다
      • 카카오 로그인을 활성화한다.
      • 필요한 동의항목을 설정한다.
        • 닉네임 필수, 카카오 계정(이메일) 필수
        • 카카오 계정은 필수 사항이지만 비즈니스 앱인 경우에만 필수로 할수 있어서 선택사항으로 지정하였다.
        • 이후에 프로필사진도 필수로 넣었다. 필요없을줄 알고 넣지 않았지만 필요하다고 해서 넣었다. 내가 백엔드에 유저 정보를 저장하는 모델을 제대로 안봐서 생긴 문제였다.
    • REST API로 로그인을 구현하였다.

      • PC, 모바일 웹 브라우저가 사용할수 있는 인증 방법은 두가지 JavaScript SDK와 REST AP가 있다.
      • REST API 방법을 선택하게된 이유는 두가지 정도로 추릴수 있다.
      • 첫번째는 프론트엔드와 백엔드를 나눠서 개발하고 있었고, 백엔드 또한 REST API 서버로 구현하고 있기 때문이었다.
      • 두번째는 액세스 토큰의 유효기간이 JS SDK가 2시간, REST API가 6시간이어서 더 길었기 때문이다.
      • 회고하면서 문서를 다시 읽어봤는데 rest api 방식의 경우 모바일 앱은 안되고 모바일 웹 브라우저(chrome, safari 등)를 통한 로그인 요청에만 지원한다고 한다. 웹앱으로 만들었으면 아마 오랫동안 헤매고 있었을듯 하다.
    • REST API를 사용하여 카카오 로그인이 진행되는 과정은 다음과 같다.

      1. 프론트엔드에서 로그인 버튼이 눌리면 카카오 서버로 인증 코드를 요청한다.
        • 로그인 페이지에서 카카오로 로그인하기 버튼을 생성하였다.
      2. 카카오 서버에서 인증코드를 전달받는다.(인증코드가 섞인 URI 반환)
        • 등록된 redirect uri로 새로고침되며 인증코드가 전달된다.
        • 페이지를 생성하고 redirect uri로 새로고침할때 해당 페이지를 라우팅할수 있게 한다.
      3. 프론트엔드에서 반환받은 인증 코드를 백엔드 서버로 전달한다.
        • 라우팅된 페이지에서 해당 url의 쿼리스트링을 분해하여 인증 코드를 가져온다.
        • 백엔드서버에 http get요청을 보낸다. (코드를 쿼리스트링으로 전달한다)
        • async를 사용하여 백엔드에서 결과가 올때까지 기다린다.
      4. 백엔드 서버에서 프론트에서 받은 인증코드로 카카오서버에 토큰을 요청한다.
      5. 카카오 서버에서 토큰을 전달받으면 백엔드 서버에서 유저를 저장하고 프론트에 사용자 정보와 함께 토큰을 전달한다.
        • 우리 프로젝트는 비즈니스 앱이 아니기 때문에 로그인과 동시에 회원가입을 진행하도록 만들었다
      6. 프론트엔드 에서 유저정보와 토큰을 저장한다.
        • 3에서 async로 기다리고있었다.
        • 결과(유저정보, 토큰)을 저장하고 메인페이지로 리다이렉트한다.
        • 로그인을 하고 난 이후 해당 토큰을 사용하여 사용자 정보를 계속확인하게 한다.
    • Redirect URI는 프론트엔드와 백엔드가 같은 주소를 가리키게 해야한다.

      • 이때 개발환경은 http:///localhost/ 에서만 사용해서 큰 문제가 되지 않다.

      • 나중에 배포하고 난 이후엔 프론트와 백엔드가 같은 주소를 가리키고 있는지 확인하기 어려워서 에러가 꽤 자주났다.

      • http, https 둘다 구분해야했고, 접근하는 주소에 대해 / 는 프론트로 /api는 백으로 연결 시켜두어서 어떤 주소로 오는지 많이 헷갈렸다.

      • 결론은 프론트엔드든 백엔드든 사용되는 주소가 같아야하고 백엔드로 요청을 보낼때만 /api 만 붙여서 요청을 보내면 된다.

        REDIRECT_URI(카카오 디벨로퍼에 저장할 값)
        http://<address>/<redirect_uri>
        https://<address>/<redirect_uri>
        
        프론트(react)에서 라우팅 하는 값(in Routes.js)
        <Route path="<redirect_uri>" component={kakaoOAuthHandler}>
        
        프론트에서 백엔드로 보내는 요청
        axios.get(`https://<address>/api/<redirect_uri>?code={code}`)
        
        백(spring boot)에서 라우팅 하는값(in socialController)
        @getMapping("<redirect_uri>")  // 매핑되는 값은 redirect_uri 그대로 사용
        public HashMap<String, Object> // 토큰이랑 유저정보를 해쉬맵으로 보냄
    • 액세스 토큰과 리프레시 토큰

      • 액세스 토큰은 API 호출 권한을 부여하고, 리프레시 토큰은 액세스 토큰을 갱신하는데 쓰인다.
      • 리프레시 토큰은 이해가 부족하여 액세스 토큰을 직접 받아 사용하는 것으로 했다.
    • 참고글

      https://developers.kakao.com/docs
      https://developers.kakao.com/docs/latest/ko/kakaologin/common
      https://data-jj.tistory.com/53