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

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

by 한코코 2022. 5. 3.

useState (state,function)이 실행되는 구조

첫째 인자값은 state를 초기화하는 값

state를 배열로 만들며 state[0]에 'aa'값이 들어가있다.

const state = React.useState('aa') 
//['aa', ()=>]와 같다

console.log(state[0]) //aa

 

두번째 인자값은 state를 변화할때 실행할 함수

console.log(state[1])를 해보면 function 형태가 나오는 것을 볼 수 있다.

따라서 두번째 인자값엔 함수형이 들어간다고 볼 수 있다. 

const Form = () => {

    const state = React.useState('aa')
    console.log(state[0])

    const handleSubmit = (e) => {
        e.preventDefault()
        state[1]('bbb')
    }
    return(
        <form onSubmit={handleSubmit}>
            {/* userid 상태와 password 상태값을 alert로 띄우고싶음 */}
            <ul>
            ...
        </form> )}
export default Form

클릭하면 aa에서 bbb로 바뀜

 

 

useState의 구조

위에서 사용한 코드에 state('bbb')를 추가했을뿐인데, 페이지는 무한반복이 되어버린다.

왜? 클래스 컴포넌트와 함수 컴포넌트의 실행 구조가 다르기 때문이다.

한번 실행시킨 뒤 재실행된 클래스 컴포넌트는 수정된 state값을 실행한 후, 바로 render()안의 코드를 읽는다.

반면에 함수 컴포넌트는 실행될때마다 내부 코드를 전부 실행한다.

const Form = () => {
    const state = React.useState('aa')
    state[1]('bbb') {/* state 수정 */}
...}

코드를 읽어보면, Form 컴포넌트의 첫째줄에서는 state를 'aa'라고 값을 초기화한다.

두번째 줄에서 state[1]값은 'bbb'라고 수정된다.

state값이 수정될때마다 호출되는 속성을 가진 useState는 다시 처음부터 코드를 읽어내려간다.

첫째줄을 읽고 state값은 다시 'aa'로 초기화 된다.

 

이 순서를 계속 반복하기때문에 무한반복 상태가 되는 것이다.

 

 

useState 코드의 축약형

위에서 설명한 것을 토대로 작성한 코드를 구조분해할당을 통해 축약하면 다음과 같은 코드가 나온다.

const Form = () => {
    const state = React.useState('aa') //['aa', ()=>{}]
    const values = state[0]
    const setValues = state[1]
    
    //구조분해할당을 통한 코드축약
    //const [values,setValues] = React.useState('aa')

 


회원가입 기능 만들어보기

내가 이해한 input에 키보드 입력 이벤트 발생부터

입력창에 입력한 글자가 뜨는게 브라우저에 렌더링 될때까지의 흐름.

이게 머리속에 그려지는게 시간이 좀 걸려서 나중에 볼때 한번에 알 수 있도록 그려보았다.

const Form2 = () => {
    const state = React.useState('aa') //['aa', ()=>{}]
    const [userid, setUserid] = useState('')
    const [password, setPassword] = useState('')

    const handleSubmit = (e) => {
        e.preventDefault()
    }

    const changeUserid = e => {
        const value = e.target.value
        setUserid(value)
    }

    const changePassword = e => {
        const value = e.target.value
        setPassword(value)
    }

    return(
        <form onSubmit={handleSubmit}>
            {/* userid 상태와 password 상태값을 alert로 띄우고싶음 */}
            <ul>
                <h2>회원가입</h2>
                <li>
                    // input의 이름을 적는 lable
                    // input의 id/name을 적는 htmlFor
                    <label htmlFor="userid">아이디</label>
                    <input type="text" name="userid" onChange={changeUserid} value={userid}/>
                    {/* onChange가 일어날때마다 최신화로 바꾸기 */}
                </li>
                <li>
                    <label htmlFor="password">비밀번호</label>
                    <input type="text" name="password" onChange={changePassword} value={password}/>
                    {/* onChange가 일어날때마다 최신화로 바꾸기 */}
                </li>
                <li>
                    <input type="submit" value="가입" />
                </li>
            </ul>
        </form>
    )
}

 

 


 

두개의 함수를 하나의 함수로 만들기

changeUserid와 changePassword 기능을 둘 다 수행할 수 있는 handleChange를 만들었다.

const state = React.useState('aa') //['aa', ()=>{}]
    const [userid, setUserid] = useState('')
    const [password, setPassword] = useState('')

    const [values,setValues] = useState({userid:'',password:''})

    const handleSubmit = (e) => {
        e.preventDefault()
    }

    const handleChange = e => {
        const value = e.target.value
        const name = e.target.name
        //{userid:'',password:'', userid:'asdf'}
        //key값이 겹치기때문에 userid는 최신화된다.
        //즉, {password:'', userid:'asdf'}
        setValues({...values,[name]:value})
    }

    // const changeUserid = e => {
    //     const value = e.target.value
    //     setUserid(value)
    // }

    // const changePassword = e => {
    //     const value = e.target.value
    //     setPassword(value)
    // }

 

 


 

Custom Hook

커스텀훅을 사용하기 위한 사전지식

<input />은 사실 객체형태로 된 자바스크립트다.

그래서 bable을 통해 실행되고 있다.

//객체로 된 자바스크립트의 예
{
    type:'input',
    props:{
        type:'input',
        name:'userid',
        onChange:()=>{},
        value:'aaaa'
    }
}

 

확인해보기

let obj={ value:'44444' }

    return(
        <form onSubmit={handleSubmit}>
            <ul>
                <h2>회원가입</h2>
                <li>
                    <label htmlFor="userid">아이디</label>
                    <input type="text" name="userid" {...obj}/>
                    //{...value}는 {value:'44444'}와 같다
                    ...

value값에 잘 적용되어있다.

 

type='text'나 name:'userid'는 원래 객체형태인데 값이 하나밖에 없으니까 중괄호를 벗기고 쓰는것임.

하지만 이게 원래 객체형태인걸 알게되면 좀더 활용적이게 쓸 수 있다.

let obj={
    value:userid,
    onChange:changeUserid
}

 

이렇게만 작성해도 input에 입력한 키값이 표시된다.

 

 

 


 

Custom Hook을 함수로 만들기

함수로 만들어 놓으면 필요할때 호출만 하면 되기때문에 편하다

const useInput = () => {
    return{
        value:'오리는 퐁실퐁실',
        onChange:(e)=>{
            console.log(e.target.value)
        }
    }
}

...
<input type="text" name="userid" {...useInput()}/>
...

 

 

 

상태값을 가진 Hook으로 만들기

Hook의 장점은 어떤 함수던지 함수 안에서 상태를 만들 수 있다는 점이다.

방금 위에서 만든 함수 안에 상태값을 만들어서 코드를 만들었다.

const useInput = (defaultValues) => {
    const [value,setValue] = useState(defaultValues)
    const onChange = (e) => {
        setValue(e.target.value)
    }
    return{
        value, // value:value 니까 생략해서
        onChange //onChange도 같은 이유로 생략
    }
}
...
const Form = () => {
    // useInput에 상태를 만들어서 필요없음
    // const state = React.useState('aa') //['aa', ()=>{}]
    const [userid, setUserid] = useState('')
    const [password, setPassword] = useState('')
    
    const id = useInput() //id라는 객체 생성 {return{value,onChange}}
    const pw = useInput() //pw라는 객체 생성
    ...
    return(
    	<input type="text" name="userid" {...id}/>
        <input type="text" name="password" {...pw}/>
    	...

 

개발자 모드에서 Hook 확인하기

댓글