본문 바로가기

React

[React] 로그인 기능 최종 구현

https://youtu.be/dFqb4KvRpNA?si=-2b0Bpht-CzUoqKA

 

본 포스팅은 John Ahn님의 유튜브 강의를 참고했습니다.

 

 

 

안녕하세요 오랜만에 왔네요 : )

 

오늘은 로그인 기존에 만들던 로그인 기능을 마무리 해보려고 합니다.

 

먼저 코드를 보여드리고 해석해보겠습니다.

 

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';
import { useNavigate } from 'react-router-dom';

function LoginPage() {
  const dispatch = useDispatch();
  const navigate = useNavigate(); // Hook from React Router
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const onEmailHandler = (event) => {
    setEmail(event.currentTarget.value);
  };

  const onPasswordHandler = (event) => {
    setPassword(event.currentTarget.value);
  };

  const onSubmitHandler = (event) => {
    event.preventDefault();

    const body = {
      email: email,
      password: password,
    };

    dispatch(loginUser(body))
      .then((response) => {
        if (response.payload.loginSuccess) {
          navigate('/'); // Use navigate instead of props.history.push
        } else {
          alert('Error');
        }
      })
      .catch((error) => {
        console.error('Login error:', error);
        alert('Login failed. Please try again.');
      });
  };

  return (
    <div
      style={{
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        width: '100%',
        height: '100vh',
      }}
    >
      <form
        style={{ display: 'flex', flexDirection: 'column' }}
        onSubmit={onSubmitHandler}
      >
        <label>Email</label>
        <input type="email" value={email} onChange={onEmailHandler} />
        <label>Password</label>
        <input type="password" value={password} onChange={onPasswordHandler} />
        <br />
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

export default LoginPage;

 

로그인 페이지의 코드입니다.

 

return (
    <div
      style={{
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        width: '100%',
        height: '100vh',
      }}
    >
      <form
        style={{ display: 'flex', flexDirection: 'column' }}
        onSubmit={onSubmitHandler}
      >
        <label>Email</label>
        <input type="email" value={email} onChange={onEmailHandler} />
        <label>Password</label>
        <input type="password" value={password} onChange={onPasswordHandler} />
        <br />
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

 

스타일은 가운데에 위에서 아래로 정렬되게 되있습니다.

 

form에 onSubmitHandler함수를 적용해서 버튼을 눌러 제출할 시

 

새로고침이 되는것을 방지했습니다.

 

input은 Email과 Password가 있는데 input창에 상태가 변경되면,

 

즉 데이터가 입력되면

 

각각 onEmailHandler와 onPasswordHandler를 발생시킵니다.

 

const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const onEmailHandler = (event) => {
    setEmail(event.currentTarget.value);
  };

  const onPasswordHandler = (event) => {
    setPassword(event.currentTarget.value);
  };

 

각 함수들은 useState기능을 활용해서

 

input으로 들어오는 데이터를 서버의 데이터로 변환하여 저장합니다.

 

 

 const body = {
      email: email,
      password: password,
    };

    dispatch(loginUser(body))
      .then((response) => {
        if (response.payload.loginSuccess) {
          navigate('/'); // Use navigate instead of props.history.push
        } else {
          alert('Error');
        }
      })
      .catch((error) => {
        console.error('Login error:', error);
        alert('Login failed. Please try again.');
      });
  };

 

body를 정의해서 데이터의 형식을 정의하고

 

redux의 dispatch함수를 이용해서 loginUser동작이 loginSucceess를 반환한다면

 

useNavigate함수를 이용해서 처음에 있던 landing페이지로 돌아갑니다.

 

로그인에 실패한다면 에러메세지를 띄웁니다.

 

localhost:3000/login

 

이것이 로그인 페이지의 UI입니다.

 

Email과 Password를 입력하면 로그인을 진행합니다.

 

Postman

 

지금은 회원가입 기능이 없으니

 

Postman으로 회원가입을하고 로그인을 진행해보겠습니다.

 

위 화면에서는 success : true를 반환하였으므로

 

해당 email과 password로 회원가입이 된 것입니다.

 

로그인 버튼을 눌렀을 때

 

 

로그인 버튼을 누르면 이렇게 시작 페이지로 이동하게 됩니다.

 

로그인이 성공적으로 된 것입니다.

 

 

 

 

 

다음은 회원가입 페이지를 만들어보겠습니다.

 

app.post('/api/users/register', async (req, res) => {
  try {
    const user = new User(req.body);
    await user.save();
    return res.status(200).json({
      success: true
    });
  } catch (error) {
    return res.json({ success: false, error });
  }
});

 

서버에서 user의 데이터가 들어오면 새로운 유저의 데이터로 저장해줍니다.

 

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { registerUser } from '../../../_actions/user_action';
import { useNavigate } from 'react-router-dom';

function RegisterPage() {
    const dispatch = useDispatch();
    const navigate = useNavigate(); // Hook from React Router

    const [email, setEmail] = useState('');
    const [name, setName] = useState('');
    const [password, setPassword] = useState('');
    const [confirmPassword, setConfirmPassword] = useState('');

    const onEmailHandler = (event) => {
        setEmail(event.currentTarget.value);
    };

    const onNameHandler = (event) => {
        setName(event.currentTarget.value);
    };

    const onPasswordHandler = (event) => {
        setPassword(event.currentTarget.value);
    };

    const onConfirmPasswordHandler = (event) => {
        setConfirmPassword(event.currentTarget.value);
    };

    const onSubmitHandler = (event) => {
        event.preventDefault();

        if (password !== confirmPassword) {
            return alert('비밀번호와 비밀번호 확인은 같아야 합니다.');
        }

        let body = {
            email: email,
            password: password,
            name: name,
        };

        dispatch(registerUser(body))
            .then((response) => {
                if (response.payload.success) {
                    navigate('/login'); // Use navigate instead of withRouter
                } else {
                    alert('Failed to sign up');
                }
            });
    };

    return (
        <div
            style={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                width: '100%',
                height: '100vh',
            }}
        >
            <form
                style={{ display: 'flex', flexDirection: 'column' }}
                onSubmit={onSubmitHandler}
            >
                <label>Email</label>
                <input type="email" value={email} onChange={onEmailHandler} />

                <label>Name</label>
                <input type="text" value={name} onChange={onNameHandler} />

                <label>Password</label>
                <input type="password" value={password} onChange={onPasswordHandler} />

                <label>Confirm Password</label>
                <input type="password" value={confirmPassword} onChange={onConfirmPasswordHandler} />

                <br />
                <button type="submit">
                    회원 가입
                </button>
            </form>
        </div>
    );
}

export default RegisterPage;

 

회원가입페이지는 로그인 페이지와 상당 부분이 비슷합니다.

 

<form
                style={{ display: 'flex', flexDirection: 'column' }}
                onSubmit={onSubmitHandler}
            >
                <label>Email</label>
                <input type="email" value={email} onChange={onEmailHandler} />

                <label>Name</label>
                <input type="text" value={name} onChange={onNameHandler} />

                <label>Password</label>
                <input type="password" value={password} onChange={onPasswordHandler} />

                <label>Confirm Password</label>
                <input type="password" value={confirmPassword} onChange={onConfirmPasswordHandler} />

                <br />
                <button type="submit">
                    회원 가입
                </button>
            </form>

 

회원가입시 필요한 Name과 비밀번호를 확인하기위해 Confirm Password가 추가되었고

 

  const onEmailHandler = (event) => {
        setEmail(event.currentTarget.value);
    };

    const onNameHandler = (event) => {
        setName(event.currentTarget.value);
    };

    const onPasswordHandler = (event) => {
        setPassword(event.currentTarget.value);
    };

    const onConfirmPasswordHandler = (event) => {
        setConfirmPassword(event.currentTarget.value);
    };

 

Handler함수도 추가되었습니다.

 

if (password !== confirmPassword) {
            return alert('비밀번호와 비밀번호 확인은 같아야 합니다.');
        }

 

만약 password가 confirmPassword와 다르다면 에러메세지를 띄웁니다.

 

  let body = {
            email: email,
            password: password,
            name: name,
        };

        dispatch(registerUser(body))
            .then((response) => {
                if (response.payload.success) {
                    navigate('/login'); // Use navigate instead of withRouter
                } else {
                    alert('Failed to sign up');
                }
            });
    };

 

데이터 형식이 변했으므로 body를 새로 정의하고

 

서버의 유저등록 동작을 요청합니다.

 

성공하면 로그인페이지로 이동하고

 

실패하면 에러메세지를 띄웁니다.

 

user_action.js에서 

export function registerUser(datetoSubmit)
{
    const request =  axios.post('/api/users/register', datetoSubmit)
    .then(response =>
         response.data
    )
    return{
        type: "REGISTER_USER",
        payload : request
    }
}

 

post요청을 하기위해 request를 새로 정의해줍니다.

 

export default function(state = {}, action){
  switch(action.type){
    case LOGIN_USER:
        return{...state, loginSuccess : action.payload}
        break;
        case REGISTER_USER:
          return{...state, register : action.payload}
          break;
        default:
            return state;
            break;
  }

 

리듀서에서도 REGISTER_USER를 만들어 줘서 

 

데이터를 업데이트 할 수 있게 해줍니다.

 

그럼 이제 회원가입을 할 준비가 되었습니다.

 

RegisterPage

 

회원가입이 성공하면

 

성공한 계정으로 로그인을 시도해봅니다.

 

회원가입된 계정으로 로그인이 성공한다면 시작페이지로 돌아갈 것입니다.

 

Landing Page

 

 

 

 

오늘은 이렇게 기존에 서버에 만들었던

 

Login과 Register 기능을 가지고

 

직접 동작할 수 있게 구현까지 해보았습니다.

 

긴 글 읽어주셔서 감사합니다!

 

'React' 카테고리의 다른 글

[React] 로그인 여부 확인 - Auth  (0) 2024.02.26
[React] 로그아웃 기능  (0) 2024.02.23
[React] Redux 기초  (0) 2024.02.21
[React] Proxy 문제 해결하기 - http-proxy-middleware  (0) 2024.02.20
[React] 라우팅 복습  (0) 2024.02.19