본문 바로가기

공부

mobx가 불변성을 지키지 않아도 되는 이유(mobx 내부 코드 살펴보기)

리덕스만 사용하다가 최근에 mobx를 공부하는 일이 생겼다.

하나의 스토어만 사용해야 하는 리덕스와 다르게 mobx는 여러개의 store를 사용할 수 있었고 reactive 방식으로 동작하는 것이 매우 매력적이었다.

그 중에서 가장 이질감이 느껴졌던 부분은

상태 업데이트 중에 불변성을 지키지 않아도 된다는 것이다.

 

리덕스처럼 새로운 객체로 감쌀 필요 없이 상태를 매우 직관적으로 그냥 할당하면 된다.

매우 편리해서 좋았지만, 한편으론 궁금했다.

도대체 어떻게 이런 일이 가능할까?

그래서 mobx 내부 소스코드를 살짝 살펴봤다.

 

 

결론적으로 말하자면 mobx는 es6의 Proxy와 Reflect를 이용해 observable 객체의 변경을 감지하고 필요한 처리를 한다.

 

es6의 Proxy와 Reflect를 알고 있어야 아래 내용을 이해할 수 있다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

 

Proxy - JavaScript | MDN

The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object.

developer.mozilla.org

 

아주 간단하게 요약하면 this.state = '1234'; 코드가 실행되면 [[set]] 이라는 트랩이 발생해서 그 트랩에 연결된 콜백이 실행되는 것이다.

마찬가지로 console.log(this.state)가 호출되면 [[get]] 트랩이 호출된다.

 

--- mobx 깃허브 코드 살펴보기

 

위 코드는 observable 객체의 내부 코드이다.

proxy의 get, set 트랩을 걸어놓은 것을 볼 수 있고

인터럽트가 걸려있는 객체들이 있는지 확인하고 아니면 proxyTrap을 발생시키고 그것도 아니면 observable이 아닌 경우로 처리한다.

 

위 코드에서 Reflect.set으로 처리한 것을 볼 수 있는데

this.target_[key] = value;로 해도 동작하지만

위처럼 작성하면 사이드이펙트(버그)가 발생할 수 있게 된다.

사이드이펙트를 최소화 하기 위해 Reflect의 set으로 처리해 구현한 것이다.

자세히 설명하자면 글이 길어지니 따로 쓰도록 하겠다.

 

여기서 interceptors은 observable 객체와 연결되어 있는 객체들이다.

observable이 변경되었고 연결된 객체들이 있다면 그 객체들에게도 변경을 알리는 구조이다.

 

get도 마찬가지로 되어 있다.

 

 

mobx의 reaction 중에는 autorun이 있는데

여기선 내부 변수가 변경되면 알아서 실행된다.

따로 디펜던시를 걸 필요가 없다.

 

어떻게 가능하냐면 마찬가지로 Proxy의 [[get]] 트랩을 이용해 콜백을 실행시키고

연결된 인터셉터들을 호출하여 업데이트를 알리는 구조이다.

 

여기까지 mobx의 내부 원리를 아주 아주 살짝 살펴봤다.

 

이것만으로도 내가 mobx에 궁금했던 원리가 상당 부분 해소되었다.

es2015의 proxy를 이해하고 있으면 상당히 많은 라이브러리, 프레임워크들의 동작 원리를 이해할 수 있게 된다. (immer, vue 등)

 

 

'공부' 카테고리의 다른 글

HTTP 2.0  (0) 2022.08.15
HTTP 1.1 Connection  (0) 2022.08.15
HTTP 리다이렉션과 부하균형  (0) 2022.07.31
HTTP 쿠키  (0) 2022.07.17
웹 서버  (0) 2022.07.10