본문 바로가기
프로그래밍/react

[220426] 회원가입창 만들기 / useEffect

by 한코코 2022. 5. 3.

React의 목적

리액트는 UI를 렌더링하는 것이 목적이다.

또한 사용자의 입력에 반응하여 필요할때  UI를 다시 렌더링하는것이다.

일반적인 컴포넌트 함수들이 이에 해당하며 리액트에 의해 재실행된다.

 

 

useEffect의 목적

화면에 무언가를 그리는 것애 관한 직접적인 행동들이 아닌것들을 Side Effect라고한다.

Hook 속해있는 함수이며 보통 이펙트라고 한다.

useEffect는 이런 이펙트 들을 처리하는것이 목표이다. (http 리퀘스트 등등..)

 

 

useEffect의 구조

loop(무한반복)이 되기 쉽기때문에 return() 바깥쪽에 위치한다.

useEffect( ()=>{}, [] );

useEffect의 첫번째 인자는 함수형태이며, 모든 컴포넌트 실행이 끝난 후 실행이 된다.

(코드를 위에서부터 아래로 읽는 습성으로 useEffect는 실행이 되지만, 안에있는 이펙트는 백그라운드로 보내버려서 실행이 안됨)

 

두번째 인자는 배열형태이며, 이 값이 바뀔경우 첫번째 인자에 있는 함수가 재실행된다.

위에 있는 함수의 경우에는 바뀔 배열값이 없기때문에 처음 시작될때 한번만 실행이 된다.

 

배열값이 아예 없을때는 useEffect가 속해있는 컴포넌트가 실행될때마다 계속해서 실행이 된다.

왜? -> 모든 컴포넌트 실행이 끝날때 useEffect가 실행되기 때문이다.

 


 

디바운싱(그룹화)

사용자 입력을 그룹화해서 처리하는것.

예) 사용자가 입력할때 하나하나 검사하지 않고, 입력을 멈출때 입력값을 한꺼번에 확인한다.

필요없는 반응들을 보지않을때, 불필요한 네트워크 트래픽을 줄이기 위해 사용

useEffect( () => {
    setTimeout( 입력하는 함수, 5000 );
    // 5초후에 작업을 수행함
    // 예) cat을 입력할 경우
    // c가 입력된 후 5초 후에 실행될 예정이었으나,
    // a가 입력될때 그 예정을 지우고 다시 5초를 세팅
    // t가 입력될때 그 세팅을 지우고 5초를 세팅
    // 더이상 입력이 없으므로 5초 후에 실행됨
    // 결론적으로 한번만!! 실행된거임.
    
    return ()=>{} //함수를 반환한다
    //이렇게 리턴값을 주는것을 클린업 함수라고 함
}, [배열]);

 

클린업 함수

useEffect 안에서 첫번째 인자로 들어간 함수의 리턴값으로 함수를 반환하는 형태를 클린업 함수라고 한다.

첫 실행을 제외하고 이펙트가 실행되려고할때, 이펙트가 실행되기전에 클린업 함수가 먼저 실행된다.

또한 해당 컴포넌트가 제거되기 전에 실행된다.

지금은 setTimeout을 이펙트로 여기고 있으므로 setTimeout이 실행되기 전에 ()=>{}가 실행된다.

(setTimout은 브라우저에 속한 함수다. 리액트와 관련 X)

 


클릭하면 비활성화가 되고 1초후에 활성화가 되는 버튼 만들기

import React,{useState, useEffect} from 'react'

const useInput = (defaultValue) => {
    const [value,setValue] = useState(defaultValue)
    const onChange = e => {
        setValue(e.target.value)
    }
    return{
        value,
        onChange
    }
}

const Form_1 = () => {
    const id = useInput('')
    const pw = useInput('')
    const [submit, setSubmit] = useState(false)

    const handleSubmit = e => {
        e.preventDefault()
        setSubmit(true) //버튼 비활성화
    }

    useEffect(
        () => {
            if(submit){
                console.log('회원가입요청!')
                setTimeout(()=>{
                    setSubmit(false) //버튼 활성화
                },1000) //1초 후에 실행
            }
        }, [submit]
    )

    return(
        <form onSubmit={handleSubmit}>
            <ul>
                <h2>회원가입</h2>
                	...
                    <input type="submit" value="가입" disabled={submit}/>
                </li>
            </ul>
        </form>
    )
}

export default Form_1

 

 

 

오류에 해당하는 에러메세지 띄우기

오류에 따라서 다음의 에러메세지를 띄우는 기능을 작성하기

  1. errors={} 객체에 내용이 비어있으면 정상적임
  2. errors={userid:'아이디는 글자수가 최소 8자 이상이여야함'}
  3. errors={password:'비밀번호는 최소 8자 이상이여야함'}
  4. errors={userid:'아이디는 글자수가 최소 8자 이상이여야함',password:'비밀번호는 최소 8자 이상이여야함'}
const Form_1 = () => {
    ...
    const [errors,setErrors] = useState({
                                    userid:'아이디는 글자수가 최소 8자 이상이여야함',
                                    password:'비밀번호는 최소 8자 이상이여야함'
                                })
                                
...
return(
    <form onSubmit={handleSubmit}>
	...
        <input type="text" name="userid" {...id}/>
        {errors.userid && <span>{errors.userid}</span>}
        //errors.userid 값이 참일때 && 뒤를 실행함

 

 

 

조건에 합당할 경우 에러메시지 지우기

 const handleSubmit = e => {
    e.preventDefault()
    setSubmit(true)
    
    let obj={}
    
    //객체 생성
    if(id.value.length < 8){
        obj.userid = '아이디는 글자수가 최소 8자 이상이여야함'
    }
    if(pw.value.length < 8){
        obj.password = '비밀번호는 최소 8자 이상이여야함'
    }
    setErrors(obj)
}

useEffect(
    () => {
        if(submit){
            console.log('회원가입요청!')
            //errors={userid:'아이디는 글자수가 최소 8자 이상이여야함',password:'비밀번호는 최소 8자 이상이여야함'}일때
            // Object.keys(errors) //['userid','password']
            // 성공시 띄울 알람
            if(Object.keys(errors).length===0){
                alert('회원가입 성공')
            }
        }
    }, [submit]
)

 

 


정규표현식을 사용해 문자열을 검색하기

/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(userid)

^ : 시작

$ : 끝

[a-zA-Z0-9._] : 배열형태로, a-z, A-Z, 0-9가 들어가는 패턴을 쓸거고, [ . _ % + - ] 도 허용할거야

+ : 글자하나일때만 사용함

+@ : [a-zA-Z0-9._]이 패턴이 끝나면 @을 넣을거야.

\. : .만 넣으면 다른 기능으로 인식하므로 \를 붙여줘야함

{2,4} : 글자는 두글자~4글자만 들어간다

test(userid) : userid에서 위 조건식을 적용해서 일치하는 부분이 있는지 확인하고 boolean 값으로 줌

 

 

최종 코드

import React,{useState,useEffect} from 'react'

const useInput = (defaultValues) => {
    const [value,setValues] = useState(defaultValues) //values하면 실행안됨
    const onChange = e => {
        setValues(e.target.value)
    }

    return{
        onChange,
        value //얘도 value여야함
    }
}

const validate = ({userid,password}) => {
    const errors = {}

    if(!userid){
        errors.userid = "이메일이 입력되지 않았습니다."
    } else if( !/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(userid) ){
        errors.userid = "입력된 이메일이 유효하지 않습니다."
    }

    if(!password){
        errors.password = "비밀번호가 입력되지 않았습니다."
    } else if (password.length < 8) {
        errors.password = "8자 이상의 패스워드를 사용해야 합니다."
    }

    return errors 
}

const Form = () => {
    const id = useInput('')
    const pw = useInput('')
    const [submit,setSubmit] = useState(false)
    const [errors,setErrors] = useState({})

    const submitHandler = e => {
        e.preventDefault()
        setSubmit(true)
        
        const input={
            userid:id.value,
            password:pw.value
        }
        console.log(input)
        setErrors(validate(input))
    }
    
    useEffect(
        ()=>{
            if(submit){
                    console.log('회원가입 요청')
                if(Object.keys(errors).length === 0){
                    alert('회원가입 완료')
                }
                setSubmit(false)
            }
        }
        ,[errors]
    )

    return(
        <form onSubmit={submitHandler}>
            <ul>
                <input type="text" name="userid" {...id}/>
                {errors.userid && <span>{errors.userid}</span>}
            </ul>
            <ul>
                <input type="text" name="password" {...pw}/>
                {errors.password && <span>{errors.password}</span>}
            </ul>
            <ul>
                <input type="submit" value="회원가입" disabled={submit}/>
            </ul>
        </form>
    )
}

export default Form

 

댓글