안녕하세요 오늘은 간단하게 짚고 넘어가야 할 리액트 에서 이벤트 핸들링에 특징 이 있어 작성하려고 왔습니다.

 

SyntheticEvent ( 합성 이벤트 )

onChange={
            (e)=>{
              console.log(e.type);
              console.log(e.target.value);

              setTimeout(()=>{
                console.warn(e.type);
              })
            }
          }

 

위와같이 코드를 작성 했을 시에 

setTimeout(()=>{

   console.warn(e.type); // null 값이 들어옵니다.

});

해당 이유는 리액트에서의 onChange , onClick 등에 들어오는 event 파라미터는 브라우저에서 사용되고있는 Event 인

https://developer.mozilla.org/ko/docs/Web/API/EventTarget

 

EventTarget

EventTarget은 이벤트를 받을 수 있으며, 이벤트에 대한 수신기(listener)를 가질 수 있는 객체가 구현하는 DOM 인터페이스입니다.

developer.mozilla.org

와는 다른 객체라고 보시면 됩니다.  해당 event 객체는 React 에서 작성한 SyntheticEvent 로 웹 브라우저에 있는 Event 를 이용한 새로운 객체입니다. 그렇기 때문에 위의 비동기 처리시에는 null 값이 되며 해당 경고가 나타납니다.

 

리액트 공식 홈페이지에서도 해당 부분을 해결하기 위해서는 e.persist 라는 함수를 사용하라고 되어있는데요 사용은 간단합니다.

 

위의 에러 코드에서 e.persist()를 호출해주면 됩니다.

          onChange={
            (e)=>{
              e.persist();
              console.log(e.type);
              console.log(e.target.value);

              setTimeout(()=>{
                console.warn(e.type);
              })
            }
          }>

 호출시에는 이제 setTimeout에서도 e.type이 노출됩니다.

e.persist를 사용하고 안하고의 차이를 결과로는 알았습니다.

하지만?   동작이 왜이렇게 바뀌는지에 대한 이유는 기본적으로 리액트에서 사용되고있는 SyntheticEvent 는 객체 풀링 방식을 사용합니다. (Object Pooling) 매 이벤트마다 해당 객체 사용되는것에 대해서 성능상의 이유로 리액트에서는 Object Pooling을 사용함으로써 객체 생성 시간을 줄이고 GC에 대한 노출도 줄이며 메모리관리에 소비되는 시간을 줄이는 방식을 사용하고 있기 때문입니다.  그렇기 때문에 객체가 호출되고 난 후에 이벤트 속성이 초기화 됩니다. 

 

그렇기 때문에 비동기로 호출하였을 경우에는 해당 객체가 비어있는 현상이 발생합니다.

그렇기 때문에 e.persist를 호출하게되면 기존에 사용하고 있던 이벤트 풀 ( Event Pool ) 에서 제거되고 사용자 코드로 사용이 됩니다.

 

 

여기까지 간단한 e.persist에 대해서 적어보았습니다. 

그냥 단순히 비동기에서 왜안되지? -> 아 호출시작부에서 e.persist를 쓰면되겠다 보다는

왜 e.persist라는 거를 써서 했을까 왜 Object Pooling을 사용했을까 등을 생각해보고자 작성하였습니다.

 

감사합니다~

+ Recent posts