본문 바로가기

Hanghae99

230115 WIL 실전 프로젝트 2주차

이번주 한일

  1. 회원가입/로그인 기능
    1. 네이버 소셜로그인
    2. 핀코드 입력 가상 키패드 구현
  2. 목표 상세 페이지
    1. 목표 상세 페이지 데이터 렌더링
    2. 목표 참가 버튼 (useMutation)
  3. 목표 조회/검색 페이지
    1. 횡스크롤/종스크롤
    2. 검색바 숨김/보이기
    3. 검색 기능 (엔터키 입력)

개요

 이번주 정말 정신없이 지나갔다. 계획대로 전혀되지 않았다. 모든 일에는 순서가 있기 마련인데 순서대로 진행되지 않았다. 뭐 하나 완벽하게 끝낸 일이 없는것 같다. 그러나 완벽이란건 세상에 없다. 완벽을 향해 개선하며 나아갈 뿐이다. 

 TIL 을 써야 한다고 생각은 하는데 코딩해야할것은 너무나 많고... 코딩 하다보면 어느새 잘 시간이 되어서 TIL 을 쓰지 못한다. 코딩 양을 줄이더라도 TIL 을써야 하는걸까? 다음 주는 조금이라도 TIL 을 쓰도록 해야 겠다.

 

1. 회원가입/로그인 기능

 1) 네이버 소셜 회워가입/ 로그인

 네이버 소셜로그인의 기본 절차는 이렇다.

 네이버 개발자 사이트 -> api 사용할 애플리케이션 등록 -> Client ID, Client Secret 발급 -> 로그인 오픈 API 서비스 환경: 서비스 URL, 네이버 로그인 Callback URL 등록 -> 프론트엔드 코딩

 

프론트엔트 (클라이언트 코딩)

클라이언트에서는 네이버 서버로 인가코드를 요청하고 그것을 서버에 전달하여 토큰을 받아오면 되는 것이다.

 

`NaverSignupButton.tsx`

import React from 'react';
import styled from 'styled-components';

import Button from '../../common/Button';
import { Colors } from '../../../styles/colors';

import NaverLogo from '../../../assets/icons/ico_Naver_logo.png';

// TODO: media query 설정
// TODO: redirect uri, client id env 파일 설정
const NaverSignupButton = () => {
  // TODO: state 추후 변경 필요
  // state는 임의의 키라고 한다. 클라이언트와 서버간의 통일된 unique key 를 입력하면되는것 같다.
  // 우리는 일단 'test'를 집어넣어 test해보았다.
  const naverStateString = 'test';

  const handleNaverSignup = () => {
  // 이 부분이 상당히 중요하다.
  // 회원가입 버튼을 클릭하면 아래의 url로 이동해서 사용자 동의를 받아 인가코드를 받아온다.
  // process.env.REACT_APP_NAVER_CLIENT_ID : 네이버 개발자 사이트에서 발급받은 Client ID를 입력해준다. 중요한 정보는 .env파일에 저장하여 함부로 공유되지 않도록 조심한다.
  // naverStateString : state 값이 입력되는 곳이다.
  // process.env.REACT_APP_NAVER_REDIRECT_URI : 인가코드를 받은 다음 돌아올 uri를 입력하는 곳이다. 네이버 개발자 사이트에서 callbak url로 설정할 수 있다.
  //                                            각 소셜 로그인 별로 이 주소를 달리하여 구분할 수 있다.
    window.location.href = `https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${process.env.REACT_APP_NAVER_CLIENT_ID}&state=${naverStateString}&redirect_uri=${process.env.REACT_APP_NAVER_REDIRECT_URI}`;
  };

  return (
    <>
      <Button
        size='large'
        background={Colors.naver}
        color='white'
        onClick={handleNaverSignup}>
        <Img src={NaverLogo} />
        NAVER로 계속하기
      </Button>
    </>
  );
};

const Img = styled.img`
  width: 20px;
  height: 20px;
  margin: 0px 10px;
`;

export default NaverSignupButton;

 

`Layout.tsx`

 어플리케이션 최상단 단위에서 api 호출을 시도하면 된다. 나는 layout에 코드를 짰지만 app.tsx 에 해도 상관없을것 같다. 그건 팀원들과 상의해서 정하면 될것 같다.

import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useQuery } from 'react-query';

import Header from './Header';
import Navigation from './Navigation';

import { userAPI } from '../apis/client';
import { userInfo } from '../recoil/atoms';
import { useSetRecoilState } from 'recoil';

export interface IChildrenProps {
  children: React.ReactNode;
}

export interface IResponeType {
  response: string | undefined;
}

function Layout({ children }: IChildrenProps) {
  const navigate = useNavigate();
  const location = useLocation();

// location.pathname은 기본 url 이후의 주소값을 불러온다. 이부분을 redirect uri로 설정하여 확인후 api 호출을 하면된다.
  if (location.pathname === '/naverlogin') {
  
  // 이 부분은 code 뒤에 값을 가져온다.
  // "http://localhost:3000/naverlogin?code=ly9xFWpJfgd1vVduuD&state=test"
  // 인가코드를 이러한 형태로 받아오는데 바로 'ly9xFWpJfgd1vVduuD' 이부분이 인가코드가 된다.
  // 따라서 code= 뒷부분을 가져오는 것이다.
    const code = new URL(window.location.href).searchParams.get('code');
    
    // useQuery를 이용해 api 호출을 했다.
    try {
      const { isLoading, data } = useQuery('naverLogin', () =>
        userAPI.getNaverSignup(code)
      );
     
     // 받아온 토큰들을 로컬스토리지에 저장한다.
     // accesstoken은 로그인 유저에게 발급되는 토큰이고
     // refreshtoken은 accesstoken이 만료되었을 때 재발급 받기위해 사용되는 토큰이다.
      localStorage.setItem('accesstoken', data.data.accesstoken);
      localStorage.setItem('refreshtoken', data.data.refreshtoken);

      // TODO: data 형식 확인후 적용
      // 이부분은 아직 확실하게 구현되지 않았다.
      const setUserInfo = useSetRecoilState(userInfo);
      setUserInfo({ id: 0, isLogin: true });

      // 모든 과정이 끝나면 메인페이지로 이동한다.
      navigate('/');
    } catch (error) {
      console.log(error);
    }
  }

  return (
    <div>
      <Header />
      <div>{children}</div>
      <Navigation />
    </div>
  );
}

export default Layout;

 

`apis/client.ts`

export const userAPI = {

  getNaverSignup: async (code: string | null) => {
  
  // get으로 인가코드를 전달해준다.
  // '/api/users/auth/naver?code=' 이 부분 뒤에 코드를 붙이면 인가코드가 전달되고
  //  서버에서는 그 인가코드를 네이버 서버에 제출해서 토큰을 발급받아 다시 클라이언트에 전달해주는 것이다.
    const { data } = await noneTokenClient.get(
      '/api/users/auth/naver?code=' + code
    );

    return data;
  },
  }

 

계속...