Study/React

[ReactJS/AXIOS] 백엔드 없이 로그인 구현하기_GET, POST

hyjang 2024. 7. 1. 02:48
728x90

현재 나는 리액트를 독학으로 공부중이다.

지금은 리액트로 서버 데이터를 주고받는 연습중인데,

이전에는 fetch 메서드로 REST API를 호출했다면 그보다 더 쉽다는 axios를 이용하여 REST API를 호출할 예정이다.

 

현재 회사의 퍼블리셔들끼리 스터디를 진행하여 프로젝트를 만들 예정이고 거기서 나는 로그인을 구현하기로 했다.

 

일단 우리는 백엔드 개발자가 아예 없는 관계로 프론트 상에서만 구현을 해야한다.

 

 

 

내 유일한 코드 리뷰어 챗 GPT는 대충 "가능은 하지만 학습용으로만 사용하고 실제로는 반드시 백엔드와 연동해라"라고 한다. 

 

일단 머리로는 아이디 비밀번호를 치면 데이터를 얻어와서(GET) 비교한 후에

맞는게 있으면 로그인, 없으면 back하면 되는거 아닌가? 했는데..

 

  • GET: 주로 데이터를 조회(read)할 때 사용된다. 로그인 정보와 같은 민감한 데이터를 URL에 포함시키지 않기 때문에, 로그인 기능에는 사용되지 않는다.
  • POST: 로그인과 같은 경우, 클라이언트가 서버 (body) 로 데이터를 전송해야 하므로 POST 메서드를 사용합니다. 이는 보안과 관련된 정보를 전송할 때 더 안전한 방법입니다.

... 그럼 post를 이용해서 구현을 해보자

 

 

일단 혼자 구현 연습을 한 후에 프로젝트에 적용하려고 한다.

 

Home
홈페이지의 Home 부분
홈페이지의 SignUp
홈페이지의 LogIn

 

기능 구현만 할 예정이기에 디자인은 신경안쓰고 구축을 했다.

 

1. Home : 리뷰 작성 페이지 

2. Log In : 로그인 페이지 (리뷰 작성을 위해)

3. Sign Up: 회원가입 페이지 (로그인을 하기 위해)

 

 

데이터 서버는 ./src/db/data.json 경로에 파일을 생성하여 json-server로 가상 데이터 서버를 만들것이다.

 

npx json-server ./src/db/data.json --port 3001
{
  "members": [
    {
      "memName": "장효영",
      "memId": "hyjang",
      "memPw": "12341234"
    },
    {
      "memName": "홍길동",
      "memId": "hong1234",
      "memPw": "12341234"
    },
    {
      "id": "5f72",
      "memName": "d",
      "memId": "s",
      "memPw": "s"
    },
    {
      "id": "9f0d",
      "memName": "s",
      "memId": "ff",
      "memPw": "aaa"
    }
  ],
  "review": [
    {
      "memName": "장효영",
      "memId": "hyjang",
      "day": "2024-05-32",
      "content": "잘 보고 갑니다."
    },
    {
      "memName": "홍길동",
      "memId": "hong1234",
      "day": "2024-05-32",
      "content": "항상 행복하세요."
    }
  ]
}

./src/db/json.data

가상 데이터 서버

이렇게 데이터서버를 열고 data.json 파일에서 수정하면 실시간으로 데이터서버에도 적용된다.

 

npm i axios
npm i react-router-dom

axios 사용과 홈페이지 Link, useNvigate 사용을 위해 react-router-dom을 설치한다. 

1. 회원가입 하기(POST)

먼저 회원가입 폼을 만든다. 

    return(
        <div className="loginWrap">
            <h1>회원가입</h1>
            <div className='loginContents'>
                <div>
                    <div className="inputWrap">
                        <label htmlFor="item_name">이름</label>
                        <input name="item_name" ref={nameRef} id="item_name" type="text" />
                    </div>
                    <div className="inputWrap">
                        <label htmlFor="item_id">아이디</label>
                        <input name="item_id" ref={idRef} id="item_id" type="text" />
                    </div>
                    <div className="inputWrap">
                        <label htmlFor="item_pw">비밀번호</label>
                        <input name="item_pw" ref={pwRef} id="item_pw" type="password" />
                    </div>
                </div>
            </div>
            <button className='signup' onClick={onSubmit}>회원가입</button>
        </div>
    )

이름, 아이디, 비밀번호 INPUT에 useRef를 이용해 DOM 접근이 가능하도록 한다. 

const navigation = useNavigate();
    const nameRef = useRef(null);
    const idRef = useRef(null);
    const pwRef = useRef(null);

    function onSubmit( ){
        const name = nameRef.current.value;
        const id = idRef.current.value;
        const pw = pwRef.current.value; 

        if(!name){
            alert("이름을 입력해주세요!"); 
            nameRef.current.focus()
            return false;
        }
        if(!id){
            alert("아이디를 입력해주세요!"); 
            idRef.current.focus()
            return false;
        }
        if(!pw){
            alert("비밀번호를 입력해주세요!"); 
            pwRef.current.focus()
            return false;
        }
        if(window.confirm("회원가입 하시겠습니까?")){ 
            axios.post('http://localhost:3001/members' , {
                memName: name,
                memId:id,
                memPw:pw
            }) 

            alert("회원가입이 완료되었습니다!")
            navigation('/')
        }

    }

로그인 구현이 우선이기 때문에 유효성검사는 건너뛰고 간단하게 입력을 안했을때만 return false 되도록 한다.

회원가입이 완료되면 완료되었다는 알럿창이 뜬 후 홈으로 이동한다.

 

axios에서 post 하는 법

axios.post(url,{보낼데이터})

 

 

이렇게 회원가입을 하면 /members 데이터서버에 김철수의 계정이 생긴다.

 

2. 로그인 하기(POST)

문제의 로그인하기.

 

일단 서버의 전체 데이터를 얻어와서(GET) 로그인으로 보낼 데이터(POST)와 비교할껀데

데이터를 간단하게 불러오기 위해서 GET 메서드를 useFetch 파일을 만들어 빼낸다.

 

./src/hooks/useFetch.js 파일을 만든다.

import axios from 'axios';
import {useState, useEffect } from 'react'

export default function useFetch(URL){
    const [data, setData] = useState([]);

    useEffect(()=>{
        axios.get(URL).then((res)=>setData(res))
    },[URL])
    
    return data
}

URL 자리에 데이터 서버 주소를 입력하면 해당 데이터를 가져올 수 있다.

이때 데이터는 배열로 보내야하기 때문에 useState 초깃값을 [] 로 넣어주자.

 

import useFetch from '../hooks/useFetch';

const item = useFetch('http://localhost:3001/members');

이렇게 하면 내가 불러오고 싶은 컴포넌트에서 위의 코드를 사용하여 데이터를 불러올 수 있다.

import './LogIn.css'
import {Link} from 'react-router-dom'
import {useState} from 'react'
import axios from 'axios';
import useFetch from '../hooks/useFetch';

export default function LogIn(){

    const item = useFetch('http://localhost:3001/members');
    const [id, setId] = useState('');
    const [pw, setPw] = useState('');

    function handleChageId(e){
        setId(e.target.value);
    }

    function handleChagePw(e){
        setPw(e.target.value);
    }

    function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{
            console.log(res)
            console.log(item)
        }) 
    }

    return(
        <div className="loginWrap">
            <h1>로그인</h1>
            <div className='loginContents'>
                <div>
                    <div className="inputWrap">
                        <label htmlFor="item_id">아이디</label>
                        <input name="item_id" onChange={handleChageId} value={id} id="item_id" type="text" />
                    </div>
                    <div className="inputWrap">
                        <label htmlFor="item_pw">비밀번호</label>
                        <input name="item_pw" onChange={handleChagePw} value={pw} id="item_pw" type="password" />
                    </div>
                </div>
                <button onClick={onSubmit}>로그인</button> 
            </div>
            <Link to={'/signup'}>회원가입</Link>
        </div>
    )
}

 

로그인을 누르면 res(보낸 데이터)와 item(전체 데이터)을 console창에 뜨도록 했는데 과연 어떻게 뜰까?

 

위가 res, 아래가 item이 console에 찍힌 모습이다.

 

여기서 우리가 봐야할 부분은 data 부분이다.

만약 data부분만 보고싶다면 res.data, item.data로 data 부분만 가져오면 된다.

 function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{
            console.log(res.data)
            console.log(item.data)
        }) 
    }

res에서 id만 보고싶다면 res.data.id를 가져오면 된다. 

    function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{
            console.log(res.data.id)
            console.log(item.data) 
        }) 
    }

 

그럼 이제부터 post로 보낼 아이디와 비밀번호, 그리고 전체 데이터에 있는 아이디와 비밀번호를

find 메서드를 이용하여 일치하는 정보를 찾아보자.

 

이때 내가 제일 처음 써본 코드는

    function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{ 
            const result = item.find((item)=> item.memId === res.data.id && item.memPw === res.data.pw);

            console.log(result);
        }) 
        .catch((err) => {
            console.error('에러 발생:', err);
          });
    }

 

였는데 계속해서  에러 발생: TypeError: item.find is not a function 이 나왔다..
이 부분은 item이 배열이 아닌 객체여서 생긴 오류라고하여 확인해보니 item.data를 써야했다. 

거기다가 res.data.id 부분은 굳이 이렇게 쓸 필요없이 내가 보낸 데이터 body 부분의 id, pw를 그냥 사용하면 됐었다.

    function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{ 
            const result = item.data.find((item)=> item.memId === id && item.memPw === pw);
            console.log(result); // 일치하는 데이터
            console.log(item.data); //전체 데이터
            console.log(res.data); //로그인 보낸 데이터
        }) 
        .catch((err) => {
            console.error('에러 발생:', err);
          });
    }

위에는 일치하는 데이터, 아래는 전체 데이터

 

만약 일치하지 않으면 undefined가 나온다. 

 

이제 setLogIn useState를 만들어 result 값이 존재하면 로그인(true), 없으면 로그인 실패(false)를 만든다!

    const [LogIn, setLogIn] = useState(false);
    function onSubmit(){
        axios.post('http://localhost:3001/members',{ id,  pw})
        .then((res)=>{ 
            const result = item.data.find((item)=> item.memId === id && item.memPw === pw);
            
            if(result){
                console.log("로그인 성공");
                setLogIn(true);
            }else{
                alert("아이디 혹은 비밀번호가 일치하지 않습니다.")
                setLogIn(false);
            }
        }) 
        .catch((err) => {
            console.error('에러 발생:', err);
          });
    }

 

로그인 실패
로그인 성공

 

이제 여기서 setLogIn을 이용하여 LogIn 값을 true 혹은 false로 지정할 수 있는데,

이 값을 이용하여 로그인이 되었는지 안되었는지를 지정할 수 있을 것이다.

 

다음 시간에는 리뷰 작성 페이지를 로그인이 됐을때 안됐을때로 나누고,

메뉴의 Log In/Sign Up을 Log Out/ My Page 로 바꿔볼것이다.