React

[React] 회원가입 구현 ( stepper, 약관동의, 유효성 검사 )

sueeee-e 2024. 10. 28. 17:17

쇼핑몰 프로젝트를 하면서 회원가입 구현 내용을 기록하고자 한다. 

 

*스타일은 mui로 해줌

 

📍stepper 

 참고하는 사이트의 회원가입에서는 

약관동의 -> 정보입력 -> 가입완료 순서로 stepper로 회원가입을 보여준다. 

그래서 mui의 stepper을 사용하기로 했다. 

 

이건 그냥 가져와서 필요없는 부분만 삭제했다.

step 개념과 Next, Back 버튼을 놔두고 나머지는 버렸다 . 

그리고 각 스텝 별로 각각의 컴포넌트를 만들어서 넣어주었다. 이 과정에서 다음 스텝으로 넘어가려면 어떠한 조건을 충족해야 한다. 

(약관동의에서 필수 약관을 모두 체크해야 next 버튼을 활성화)

(정보입력에서 각 유효성 검사를 만족한 텍스트필드를 입력했을 때 next 버튼 활성화)

 

import React, { useState } from 'react';
import { Box, Stepper, Step, StepLabel, Button, Typography, Divider } from '@mui/material';
import Agreement from '../component/Agreement';
import InputSignup from '../component/InputSignup';

const steps = ['약관동의', '정보입력', '가입완료'];

export default function Signup() {
  const [activeStep, setActiveStep] = useState(0);
  const [isAgreed, setIsAgreed] = useState(false);
  const [isValidInput, setIsValidInput] = useState(false);

  const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
  };

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1);
  };

  const handleAgreementChange = (isChecked) => {
    setIsAgreed(isChecked);
  };

  const handleValidityChange = (isValid) => {
    setIsValidInput(isValid);
  };

  return (
    <Box sx={{ width: '100%' }}>
      <Typography align='center'>회원가입</Typography>
      <Divider sx={{marginBottom:3, }} />
      <Stepper activeStep={activeStep}>
        {steps.map((label) => (
          <Step key={label}>
            <StepLabel>{label}</StepLabel>
          </Step>
        ))}
      </Stepper>
        <Box sx={{ margin:2, height:'auto'}}>
          {activeStep === 0 && <Agreement onAgreementChange={handleAgreementChange} />}
          {activeStep === 1 && <InputSignup onValidityChange={handleValidityChange} />}
          {activeStep === 2 && <Typography>가입이 완료되었습니다!</Typography>}
        </Box>
        <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
          <Button
            color="primary"
            disabled={activeStep === 0}
            onClick={handleBack}
            sx={{ mr: 1 }}
          >
            Back
          </Button>
          <Box sx={{ flex: '1 1 auto' }} />
          <Button onClick={handleNext} disabled={(activeStep === 0 && !isAgreed) || (activeStep === 1 && !isValidInput)}>
            {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
          </Button>
        </Box>
    </Box>
  );
}

 

 

 

📍약관동의 ( 전체동의, 필수, 선택 )

약관동의 내용은 아직 없는 상태라 우선 체크박스만 가져와서 구현했다. 

✔️ 요구사항

- 전체 동의를 눌렀을 때 모두 체크되어야 하고 하나라도 해제되었을 경우 전체동의의 체크도 해제

- 필수 약관을 모두 체크해야 next 버튼을 활성화시켜주는 함수 넘겨주기 

- 선택은 그냥 뭐 없을 것 같당..

 

구글링해보니까 다들 const data = [ id:0, title:ddf,, ... ] 데이터를 받아서 하던데 일단 나는 데이터도 없고 ,, 그냥 체크박스만 확인해보는 거니까 ,,? 이대로 진행

 

전체 동의 - handleAllChecked 

필수 - handleRequiredChange

선택 - handleOptionalChange 

 

각각의 함수를 만들어서 요구사항을 충족시켜주었다. 

 const handleAllChecked = (event) => {
        const isChecked = event.target.checked;
        setAllChecked(isChecked);
        setRequiredChecked({
            필수1: isChecked,
            필수2: isChecked,
        });
        setOptionalChecked(isChecked);
    };

    const handleRequiredChange = (event) => {
        const { name, checked } = event.target;
        setRequiredChecked((prevState) => ({
            ...prevState,
            [name]: checked,
        }));
    };

    const handleOptionalChange = (event) => {
        setOptionalChecked(event.target.checked);
    };

 

allRequiredChecked 라는 함수를 만들어서 useEffect()로 조건에 만족하면 onAgreementChange를 props로 버튼 활성화 상태를 업데이트해준다. 

📍회원가입 - 유효성 검사

회원가입 유효성검사와 관련된 포스팅이 아주 많아서 그 중에 가장 기본적인 구조를 참고해서 구현했다. 

useState를 남발하는 듯이 했지만 이게 그래도 직관적인 것 같아서 이렇게 구성했고 이후에 기능별 useState를 묶어서 관리하거나 react-hook-form을 사용해서 리팩토링을 진행해보면 좋을 것 같다. 

 const [id, setId] = useState('')
 const [idError, setIdError] = useState('');
 const [isIdValid, setIsIdValid] = useState(false);
 
 const handleIdChange = (e) => {
        const value = e.target.value;
        setId(value);
        if (/^[A-Za-z]{5,}$/.test(value)) {
          setIsIdValid(true);
          setIdError('');
        } else {
          setIsIdValid(false);
          setIdError('영문으로 5자 이상 입력해주세요');
        }
    };
    
//return
<TextField  
    size="small" 
    name='id'
    label='id'
    fullWidth
    value={id}
    onChange={handleIdChange}
    helperText={idError || (isIdValid && '사용가능한 아이디입니다.')}
    error={!!idError}/>

 

이런 식으로 반복해주면 된다.

이것도 마찬가지로 isAllValid 라는 함수를 props로 넘겨주어 next 버튼을 활성화 여부를 알려준다.

이후 서버 연결하면 중복확인 버튼을 이용해서 유효성 검사해주는 것으로 바꿔볼 생각이다!

 

🙏🏻 회원가입 참고 포스팅

https://velog.io/@leemember/%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC

화면에선 안보이지만 전부 유효한 텍스트를 입력해야 next 버튼이 활성화되어 다음 단계로 넘어갑니당./