SyntheticEvent와 비동기(setState)

김민석·2021년 6월 6일
0

react

목록 보기
11/11

아래 코드는 custom hook으로,
form을 다루는 컴포넌트들에서 input을 관리하는 기능을 묶어서 정의한 것이다.

import { useState, useCallback } from "react";

const useInput = (initialInput) => {
  const [input, setInput] = useState(initialInput);

  const onChangeInput = useCallback((e) => {
    // const { name, value } = e.target;
    console.log(e);
    setInput((input) => {
      return {
        ...input,
        [e.target.name]: e.target.value,
      };
    });
  }, []);

  return [input, onChangeInput];
};

export default useInput;

그런데 input을 작성하다 보면 아래와 같은 에러가 뜬다.



아래와 같이 바꾸니 문제가 해결되는 것을 알 수 있었다.
그러나 이유를 이해하지 못했기 때문에, 찾아보기로 하였다.


synthetic Event

react에서 이벤트 핸들러는 모든 브라우저에서 동일하게 작동하는 것을 보장하기 위해 SyntheticEvent 객체로 브라우저의 event를 감싸서 전달한다고 한다.

그런데 이 객체가 작동하는 방식이 신기하다.
이 객체는 성능상의 이점을 위해 계속해서 재사용되는 방식으로 이루어진다.

이를 event pooling이라고 하더라. (다음 버전의 react에서 사라질 예정이라고 한다.)

간단하게 말하자면 이벤트 핸들러가 쭉 실행되고 나서 SyntheticEvent 객체의 모든 요소를 nullify하는 식으로 비운다고 한다.

object pooling 설명 링크

이 작동 방식 설명을 위해 react 공식 사이트에는 다음과 같은가 있었다.

function handleChange(e) {
  // This won't work because the event object gets reused.
  setTimeout(() => {
    console.log(e.target.value); // Too late!
  }, 100);
}

즉 setTimeout 안의 e.target.value는 원하는 대상을 지칭하지 않게 된다.


답을 찾았다.

react에서

  • setState가 비동기적으로 시행된다는 것
  • SyntheticEvent가 object pooling 방식에 의해 계속해서 재사용 된다는 점*

    *즉 이벤트 핸들러가 시행되고 나면 객체 내부의 내용이 초기화 된다는 점.

이 두 가지에 의해 맨 꼭대기에서 확인할 수 있는 error가 뜬 것이다.

따라서 그 내부의 값을 우선 다른 변수에 할당 한 후,
그 할당한 값을 이용해서 state를 변경하면 오류가 없이 잘 작동하는 것을 알 수 있었다.

0개의 댓글