React-hook-form 활용하여 패스워드 재설정 구현

Jayden ·2023년 11월 14일
  1. 구현할 기능 설명
  • 패스워드 변경 페이지에서 현재 패스워드와

    변경하고자 하는 패스워드와, 패스워드 확인값을 입력 후 변경하는 작업을 진행하고 싶습니다.

요구사항 조건 :

조건 1) 변경할 패스워드 에는 영문자, 숫자가 포함되어야 하고 6자이상, 12자 이하로 비밀번호 입력 조건을 제한(정규식 사용), 조건에 어긋날 경우 하단잘못된 패스워드 입니다.에 메시지 출력

조건 2) 변경할 패스워드 확인란에는 좌측에 입력한 패스워드와 동일한지 확인하는 작업을 진행한다.
조건에 어긋날 경우 하단에 패스워드가 일치하지 않습니다. 메시지 출력

조건 3) 각각 항목 입력시 실시간으로 유효성을 체크하고 유효성에 어긋날 경우, 입력란 하단에 메시지를 표시한다.

  1. 코드 구현
  • react-hook-form 페이지를 참고하여 작성하였습니다.
  • 입력시에 실시간으로 (리액트나 자바스크립트에 onChange 이벤트 처럼) 유효성을 체크하도록
    const {register, handleSubmit, watch, formState : {isSubmitting, isValid, errors}} = useForm<any>({mode : "onChange"}) 처럼 useForm 우측에 mode를 정의합니다.

(if, mode : "onChange" 를 정의하지 않을 경우 버튼 클릭시, 즉 submit 이벤트 발생시 유효성 한꺼번에 체크
=> 에러메시지 한꺼번에 표시 => 조건 3)에 부합하지 않음

import { styled } from "styled-components"
import { AlertComponent, Button, H1, H4, Input, Wrapper } from "../common/Style"
import { useRef, useState } from "react"
import axios from "axios"
import { API } from "../../util/common"
import { useForm } from "react-hook-form"
import { t } from "i18next"

/* 계정 설정 - 패스워드 변경 페이지 */

const ContentsWrapper = styled.div`
    width : 1140px;
    float : right;
`

const Border = styled.div`
    width : 906px;
    height : 1px;
    background: #C5C6CC;
    margin-left : 140px;
    margin-right : 94px;
`
const SupportText = styled.p`
    margin-top : 10px;
    font-size : 12px;
    color : var(--jled, #B80000);
`

const PasswordSubmitButton = styled(Button)<{ disabled: boolean }>`
  background-color: ${({ disabled }) => (disabled ? "#C5C5CC" : "#B80000")};
`;

export default function Password(){

    const [isPopupOpen, setIsPopupOpen] = useState(false)
    const [message, setMessage] = useState('')
    
    //패스워드 영문자 + 숫자 조합으로 규칙을 정했으므로, 특수 문자가 입력할때는 지울려고 합니다.
    const regexSpecialSign = /[{}[\]\/?.,;:|)*~`!^_+<>@#$%&\\=('""]/g;

    const {register, handleSubmit, watch, formState : {isSubmitting, isValid, errors}} = useForm<any>({mode : "onChange"});


    const passwordRef = useRef<string | null>(null);
    passwordRef.current = watch('new_pw');

 /*** 패스워드 변경 API 호출 함수 ****/
    const changePwordSubmit = async (data : any) => {

        const options = {
            headers : {
                "Authorization" : 'Bearer -----------',
            }
        }

        const body = {
            ...data, 
            dbidx : sessionStorage.getItem("pid")
        }

        console.log(body);
      
        try{
            const {data, status} = await axios.post(`${API}`, body, options)
            console.log(data)
            if(status === 200){
                if(data.outcode !== 0){ 
                    setMessage(data.msg);
                    setIsPopupOpen(true);
                }
            }
        }
        catch(e : unknown){
            if(e instanceof Error)
            console.log(e.message)
        }
    }

 /**********   View ***********/
    return(
        <ContentsWrapper>
            <form onSubmit={handleSubmit(changePwordSubmit)}>
            <H1 marginTop={51} marginLeft={130}>{t('패스워드 변경')}</H1>
            <Wrapper width={891} marginTop={46} marginLeft={140} marginBottom={49}>
                <H4 width={891} marginBottom={8}>{t('현재 패스워드')}</H4>
                <Input type ="password" borderRadius={12} width={891} placeholder={t('현재 패스워드')}
                {...register('cur_pw', {
                     required: '현재 패스워드를 입력하세요.' 
                }) } />
                {/* <SupportText>{errors.cur_pw && (<span>{errors.cur_pw.message!.toString()}</span>)}</SupportText> */}
            </Wrapper>
            
            <Border/>
            <Wrapper display="flex">
                <Wrapper width={419} marginTop={40} marginLeft={140} marginRight={53} >
                    <H4 width={419} marginBottom={8}>{t('변경 패스워드')}</H4>
                    <Input type ="password" 
                           borderRadius={12} 
                           width={419} 
                           placeholder={t('영문자, 숫자 조합 최소 6글자 최대 12자 입력')}
                                {...register('new_pw', {
                                    required : true,
                                    pattern : {
                                        value :  /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,12}$/,
                                        message : "잘못된 패스워드 입니다."
                                    },
                                    onChange: (e) => {
                                      
                                      //위에서 정의한 특수 문자(regexSpecialSign)가 입력되면 지울려고 합니다.
                                        const value = e.target.value;
                                        const sanitizedValue = value.replace(regexSpecialSign, ''); // 패턴에 일치하는 문자열을 제거
                                        e.target.value = sanitizedValue; // 제거된 값을 다시 입력란에 할당
                                      },
                                })}
                    />
                    <SupportText>
                        <SupportText>{errors.new_pw && (<span>{errors.new_pw.message?.toString()}</span>)}</SupportText>
                    </SupportText>
                </Wrapper>
                <Wrapper width={410} marginTop={40}>
                    <H4 width={419} marginBottom={8}>{t('패스워드 확인')}</H4>
                    <Input type ="password" 
                           borderRadius={12} 
                           width={419} 
                           placeholder={t('패스워드 확인')}
                                {...register('new_pw_verify', {
                                    required : true,
                                    validate : (value) => (value === passwordRef.current) || "패스워드가 일치하지 않습니다.",
                                    onChange: (e) => {
                                        const value = e.target.value;
                                        const sanitizedValue = value.replace(regexSpecialSign, ''); // 패턴에 일치하는 문자열을 제거
                                        e.target.value = sanitizedValue; // 제거된 값을 다시 입력란에 할당
                                      },
                                })}/>
                     <SupportText>
                        {errors?.new_pw_verify?.message?.toString()}
                     </SupportText>
                </Wrapper>
            </Wrapper>
            <PasswordSubmitButton
            type="submit"
            borderRadius={5}
            width={191}
            marginTop={61}
            marginLeft={839}
            disabled={!isValid || isSubmitting}
            >
            {t('저장')}
            </PasswordSubmitButton>
                        </form>
                        {isPopupOpen && <AlertComponent message={message} popupClose={setIsPopupOpen}/>}
        </ContentsWrapper>
      
profile
프론트엔드 개발자

2개의 댓글

comment-user-thumbnail
2023년 11월 14일

좋은 글이네요. 공유해주셔서 감사합니다.

1개의 답글