triplus) 로그인 페이지 완성

하쿄이_hakyoiii·2021년 12월 27일

프로젝트일지

목록 보기
1/12

코드스테이츠 final project

Redux thunk에 대한 이해

로그인 상태를 Redux로 관리하려고 했는데, 아무래도 서버통신 부분이다 보니 비동기처리가 필요했다.

이전에 하던것처럼 액션객체를 바로 반환하니까 값이 제대로 안들어가는 오류가 있었다.

조금 찾아보니 Redux thunk를 사용해서 프로미스를 리턴하는 형식으로 해보면 어떨까 싶었다.

export const adminUser = (dataTosubmit) => (dispatch) => {
  axios
    .post(`http://localhost/login`, dataTosubmit)
    .then((response) => response.data)
    .then((res) => {
      dispatch({
        type: ADMIN_USER,
        payload: { success: res.success, message: res.message },
      });
    });
};

원래의 Redux는 store에 객체형태만 저장이 가능하다. 하지만 Thunk를 사용하면 함수형식도 인식이 가능하게 만들어준다. 이렇게 상태관리를 도와주도록 하는 미들웨어들이 있다는 것을 알았다.

로그인 기능 구현 완료

로그인 기능 구현을 완료했다. 서버쪽도 같이 작성하다보니 공부가 조금 필요했다. 서버 컨트롤러를 작성하고 포스트맨으로 테스트를 해봤는데 결과가 잘 나오는 걸 확인했다.

그 후 클라이언트에서 값을 담아 보내서 테스트를 해봤는데, 요청이 제대로 들어가지 않는 에러가 발생했다. prefilght부터 거절당했다...!ㅜ

cors에 필요한 origin을 서버에 잘 넣어두어서 origin 문제는 아니겠고, 분명히 다른 문제가 클라이언트에 있다고 생각돼서 혹시 url을 잘못 입력했나 보았다.

아니나 다를까 http통신을 해야하는데 https로 잘못 적어놓고 있었다. 변수명도 REACT_APP_HTTPSURL이라고 해놔서 변수명과 값을 다 바꿔줘야 했다. 어차피 EC2서버로 연결할거긴 하지만 로컬에서 테스트해봐야해서 일단은 바꿔서 테스트를 해봤다. 결과는 성공!

서버에서 받아오는 메시지로 경고창도 띄워놓으니까 제법 완성도 있는 로그인창이 되었다.

로그인창 스크린샷

import React, { useState } from 'react';
import styled from 'styled-components';
import LoginBtns from './LoginBtns';
import LoginId from './LoginId';
import LoginPw from './LoginPw';
import { useDispatch, useSelector } from 'react-redux';
import { loginUser } from '../../redux/login/action';
import { useNavigate } from 'react-router-dom';

const SectionBlock = styled.div`
  max-width: 100%;
`;

export default function LoginSection(props) {
  // ---- 상태정의 ----
  const state = useSelector((state) => state.loginReducer);
  const { isLogin } = state;
  const [userId, setUserId] = useState('');
  const [userPw, setUserPw] = useState('');
  const dispatch = useDispatch();
  let navigate = useNavigate();

  // ---- navigate ----
  if (isLogin) {
    navigate('/');
  }

  // ---- 이벤트 핸들러 ----
  const handleIdChange = (e) => {
    setUserId(e.target.value);
  };
  const handlePwChange = (e) => {
    setUserPw(e.target.value);
  };
  const handleLoginClick = (e) => {
    e.preventDefault();
    let body = {
      userId: userId,
      password: userPw,
    };
    dispatch(loginUser(body));
  };
  const handleSignupClick = () => {
    navigate('/signup');
  };

  return (
    <SectionBlock>
      <LoginId userId={userId} handleIdChange={handleIdChange} />
      <LoginPw userPw={userPw} handlePwChange={handlePwChange} />
      <LoginBtns handleLoginClick={handleLoginClick} handleSignupClick={handleSignupClick} />
    </SectionBlock>
  );
}

이번엔 세세하게 규칙을 짜서 그런지 하나하나 신경써가며 코드를 작성했더니 금방 끝날 줄 알았는데 한두시간이 더 걸렸다. 팀 규칙을 짜고, 그걸 지키면서 코드를 짜는 게 쉬운일이 아니라는 생각을 했다. 근데 코드 작성이 깔끔해지고 통일성이 있는게 너무 보기좋다!

코드리뷰시간에 일어난 일

우리팀은 저녁에 다같이 모여서 서로의 코드를 보며 merge를 하는데, 애초에 정했던 UI가 일반적이지 않다는 의견이 나와 관리자 로그인을 대폭 수정해야 했다.

그래서 로그인페이지에 들어있던 관리자 로그인 부분을 떼서, /admin 경로로 이동할 경우에 관리자 로그인 모달창이 보여지게 만들었다.

어드민화면 스크린샷

모달창 옮기는 건 어렵지 않았지만, admin페이지로 이동하고 최초 렌더링때 모달창이 보여져야해서 세세한 설정(라우팅, 상태관리 등등)이 조금 있었다.

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import ModalTemplete from '../components/admin/adminmodal/ModalTemplete';
import { adminOpen } from '../redux/admin/action';

export default function AdminPage() {
  const isOpen = useSelector((state) => state.adminOpenReducer);
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(adminOpen());
  }, [dispatch]);
  return <div>{isOpen ? <ModalTemplete /> : null}</div>;
}

함수가 연속으로 호출돼서 무한루프에 빠질 수 있다는 오류메시지도 나왔다.

if (isAdmin) {
    return () => {
      navigate('/admin');
    };
  }

콜백함수로 리턴하지 않고 바로 navigate를 해줘서 났던 오류였다. 위처럼 고치고 나니까 해결됐다.

조금 더 연구해볼 문제인 것 같다.

profile
Hello I'm front-end engineer hakyoung song!

0개의 댓글