setState 비동기

임찬수·2021년 11월 29일
0

4개의 input값을 참조에 회원가입 버튼이 활성/비활성화 되는 동작을 구현하려했다.
setState를 사용하여 각 input의 name값으로 값에 접근하여 변경 할 수 있도록 잘 처리했다고 생각했다.

그런데 문제가 생겼다.

4개의 input에 키보드 이벤트가 발생할때마다 값을 콘솔에 찍었는데
하나씩 값이 밀려 찍힌다. 이러면 정확하게 가입하기 버튼의 동작을 제어할수 없는데..

구글링, 아무나잡고 물어보기를 시전하여 setState가 비동기라는 사실을 알게되었다.
때문에 내가 값을 변경하면 console.log가 먼저 실행되고 비동기로 대기중이었던 setState의 동작이 나중에 실행되는것이었다.

문제의 코드

const SignUp = () => {
  const inputsObj = {
    user_email: '',
    user_nick: '',
    user_pw: '',
    user_check_pw: ''
  }

  const [inputValues, setInputs] = useState(inputsObj)
  const [isPass, setPass] = useState(true)

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

  const checkInputValid = () => {
    const pass = Object.values(inputValues).some(value => value === '')
    setPass(pass)
  }

  const handleKeyUpInput = (e) => {
    setInputs({
      ...inputValues,
      [e.target.name]: e.target.value
    })

    console.log(inputValues)
  }

  const handleClickSignUp = () => {
    console.log(inputValues)
  }

  return (
    <SignUpArea>
      <Grid 
            is_container 
            margin="50px auto 10px auto"
            padding="30px 40px"
            border="border: 1px solid var(--border-color)"
            bg="#fff"
      >
        <Logo maxWidth="180px" margin="0 auto 30px auto"/>

        <Text size="16px" color="#aaa" margin="0 0 20px 0" center bold>
          매거진스타그램에 가입하세요!
        </Text>

        <Grid margin="0 0 6px 0">
          <Input _onKeyUp={handleKeyUpInput} name="user_email" type="text" placeholder="사용자 이메일" />
        </Grid>

        <Grid margin="0 0 6px 0">
          <Input _onKeyUp={handleKeyUpInput} name="user_nick" type="text" placeholder="닉네임" />
        </Grid>

        <Grid margin="0 0 6px 0">
          <Input _onKeyUp={handleKeyUpInput} name="user_pw" type="password" placeholder="비밀번호" />
        </Grid>

        <Grid margin="0 0 14px 0">
          <Input _onKeyUp={handleKeyUpInput} name="user_check_pw" type="password" placeholder="비밀번호 확인" />
        </Grid>

        <Grid>
          <Button _onClick={handleClickSignUp} width="100%" size="15px" bold disabled={isPass}>가입하기</Button>
        </Grid>

      </Grid>

      <Grid 
        is_flex
        is_container 
        padding="20px 40px"
        border="border: 1px solid var(--border-color)"
        bg="#fff"
      >
        계정이 있으신가요? <Button ver="white" size="15px" bold>로그인</Button>
      </Grid>
    </SignUpArea>
  )
}

클래스 컴포넌트에서의 해결

이전 클래스형 컴포넌트에서는 setState의 두번째 인자 값으로 변경이 된 상태값에 접근이 가능하였다.

 <button
          onClick={() => {
            this.setState({ number: number - 1 }, () => { //변경된 부분2
              console.log(this.state);
              this.alertNumber();
            });
          }}
        >
          -1
 </button>

그러나 내 코드는 함수형 컴포넌트에서 hooks를 사용하고있는데 이때의 setState는 두번째 인자를 지원하지 않았다.

함수형 컴포넌트에서의 해결

이런 문제는 useEffect()로 해결이 가능하였다. useEffect()의 두번째 인자로 배열에 감시하고자 하는 값을 참조하게하면 상태가 변할때의 값을 정확히 참조 할 수있기 때문에 키보드 이벤트 발생시에 checkInputValid를 실행하게하면 해결 할 수 있는 문제였다.

또, 다른 조언 중에 useCallback()으로도 해결이 가능하다고 했는데 useCallback을 한번도 사용해보지 못했고 어떤 개념인지 몰랐기 때문에 앞으로 공부해봐야겠다.

참고할만한 포스팅

결론

useEffect() 잘 사용하고, useCallback() 공부해

profile
프론트엔드 개발자가 되기 위한 정보를 정리합니다.

0개의 댓글

관련 채용 정보