본문 바로가기
WebDev/항해99

실전프로젝트 로그인 컴포넌트 분리 로직

by S.AHA_dev 2023. 8. 22.
728x90
반응형

로그인은 UI는 적었지만 분리를 안해놔서 가독성도 안좋았고 유지보수하기가 힘들었음

그래서 이제 했던 파트들은 점점 분리와 최적화에 신경을 쓰려고 한다.

export interface SignIn {
  email: string;
  password: string;
}
interface ErrorMessage {
  message?: string;
}
const validateEmail = (email: string): boolean => {
  const emailRegex = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
  return emailRegex.test(email);
};
const validatePassword = (password: string): boolean => {
  const passwordPattern = /^(?=.*\d)(?=.*[a-zA-Z]).{8,}$/;
  return passwordPattern.test(password);
};

const SignInUi = () => {
  const dispatch = useDispatch();
  const router: NextRouter = useRouter();
  const [signInState, setSignInState] = useState<SignIn>({
    email: '',
    password: '',
  });
  const [error, setError] = useState<ErrorMessage>({
    message: '',
  });

  const signInMutation = useMutation(userLogin, {
    onSuccess: (data) => {
      dispatch(LOGIN_USER(data));
      router.push('/');
    },
    onError: (error: AxiosError) => {
      if (error.response && error.response.data) {
        setError((prev) => ({ ...prev, password: error.response?.data }));
        alert('아이디와 비밀번호를 다시 확인해주세요');
      }
    },
  });

  const moveHomeBtn = React.useCallback(() => {
    router.push('/');
  }, [router]);

  const handleInputChange = React.useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const { name, value } = e.target;
      setSignInState((prevSignInState) => ({
        ...prevSignInState,
        [name]: value,
      }));
    },
    []
  );

  const handleLogin = (e: FormEvent) => {
    e.preventDefault();
    let errors: ErrorMessage = {};

    if (!validateEmail(signInState.email)) {
      if (!validatePassword(signInState.password)) {
        errors.message = '아이디와 비밀번호를 다시 확인해주세요';
      }
    }

    if (Object.keys(errors).length > 0) {
      setError(errors);
      return;
    } else {
      setError({ message: '' });
    }
    const sendData = {
      email: signInState.email,
      password: signInState.password,
    };
    signInMutation.mutate(sendData);
  };

  return (
    <SignInSection>
      <SignInContainer onSubmit={handleLogin}>
        <MainHeadText onClick={moveHomeBtn}>HAPOOM</MainHeadText>

        <SignInInput
          signInState={signInState}
          handleInputChange={handleInputChange}
        />
        {error.message && (
          <TextErrorParagraph>{error.message}</TextErrorParagraph>
        )}

        <SignInControls signInState={signInState} />

        <SocialLogin />
      </SignInContainer>
    </SignInSection>
  );
};

export default React.memo(SignInUi);

먼저 부분 부분으로 잘라서 컴포넌트화 시킨 후 함수도 따로 컴포넌트쪽에 맡기기로 했음 

export interface SignIn {
  email: string;
  password: string;
}
interface ErrorMessage {
  message?: string;
}
const validateEmail = (email: string): boolean => {
  const emailRegex = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
  return emailRegex.test(email);
};
const validatePassword = (password: string): boolean => {
  const passwordPattern = /^(?=.*\d)(?=.*[a-zA-Z]).{8,}$/;
  return passwordPattern.test(password);
};

const SignInUi = () => {
  const dispatch = useDispatch();
  const router: NextRouter = useRouter();
  const [signInState, setSignInState] = useState<SignIn>({
    email: '',
    password: '',
  });
  const [error, setError] = useState<ErrorMessage>({
    message: '',
  });

  const signInMutation = useMutation(userLogin, {
    onSuccess: (data) => {
      dispatch(LOGIN_USER(data));
      router.push('/');
    },
    onError: (error: AxiosError) => {
      if (error.response && error.response.data) {
        setError((prev) => ({ ...prev, password: error.response?.data }));
        alert('아이디와 비밀번호를 다시 확인해주세요');
      }
    },
  });

  const moveHomeBtn = React.useCallback(() => {
    router.push('/');
  }, [router]);

  const handleInputChange = React.useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const { name, value } = e.target;
      setSignInState((prevSignInState) => ({
        ...prevSignInState,
        [name]: value,
      }));
    },
    []
  );

  const handleLogin = (e: FormEvent) => {
    e.preventDefault();
    let errors: ErrorMessage = {};

    if (!validateEmail(signInState.email)) {
      if (!validatePassword(signInState.password)) {
        errors.message = '아이디와 비밀번호를 다시 확인해주세요';
      }
    }

    if (Object.keys(errors).length > 0) {
      setError(errors);
      return;
    } else {
      setError({ message: '' });
    }
    const sendData = {
      email: signInState.email,
      password: signInState.password,
    };
    signInMutation.mutate(sendData);
  };

  return (
    <SignInSection>
      <SignInContainer onSubmit={handleLogin}>
        <MainHeadText onClick={moveHomeBtn}>HAPOOM</MainHeadText>

        <SignInInput
          signInState={signInState}
          handleInputChange={handleInputChange}
        />
        {error.message && (
          <TextErrorParagraph>{error.message}</TextErrorParagraph>
        )}

        <SignInControls signInState={signInState} />

        <SocialLogin />
      </SignInContainer>
    </SignInSection>
  );
};

export default React.memo(SignInUi);

프랍스가 없는 부분은 메모로 최적화를 걸고 함수들은 재생성되지않게 useCallback으로 마무리! 리렌더 되지 않는 걸 확인 후 다음 작업 가잣! 

반응형