"리액트라는 이름은 좋은데, 그래서 정확히 뭐가 뭐에 반응한다는 겁니까?"
새로 팀에 합류한 엔지니어, 크리스가 회의 중에 날카로운 질문을 던졌다. 그는 백본(Backbone.js) 전문가였고, 리액트의 급진적인 아이디어에 아직 반신반의하고 있었다.
"백본도 마찬가지 아닌가요? 모델 데이터가 바뀌면, listenTo로 등록된 뷰가 반응해서 화면을 업데이트하잖아요. 똑같은 거 아닙니까?"
그의 질문은 리액트의 정체성을 꿰뚫는 핵심이었다. 만약 리액트가 단순히 백본의 이벤트 시스템을 다른 이름으로 포장한 것에 불과하다면, 이 모든 소동은 무의미한 일이었다.
조던 워크가 대답에 나섰다.
"크리스의 지적은 중요합니다. 하지만 둘 사이에는 근본적인 차이가 있습니다. 바로 '무엇에' 반응하는가, 그리고 '어떻게' 반응하는가에 대한 철학의 차이죠."
그는 화이트보드에 두 개의 시스템을 나란히 그렸다.
백본의 반응(Listening)
- 조던은 백본의 모델을 그리고, 그 주변에 여러 개의 뷰를 그렸다.
- 그는 모델의 특정 속성(예:
username,likeCount)에서 각 뷰로 향하는 여러 개의 가느다란 화살표를 그렸다. - "백본은 '미시적인 변화'에 귀를 기울입니다.
View A는username의 변화에만 귀를 기울이고,View B는likeCount의 변화에만 귀를 기울이죠. 각 뷰는 자신이 관심 있는 특정 이벤트만을 선택적으로 듣습니다. 이것이 '리스닝'입니다."
리액트의 반응(Reacting)
- 조던은 하나의 거대한 '상태(State)' 객체를 그렸다.
- 그는 이 상태 객체에서, UI 전체를 나타내는 단 하나의 컴포넌트 트리로 향하는 굵고 단단한 화살표 하나만을 그렸다.
- "리액트는 미시적인 변화에 관심이 없습니다.
username이 바뀌었는지,likeCount가 바뀌었는지는 중요하지 않아요. 리액트는 오직 단 하나의 사실, 즉 '상태 객체 자체가 이전과 다른 새로운 객체로 대체되었다'는 거시적인 변화에만 반응합니다."
그의 설명은 명확했다. 백본은 수십 개의 작은 종소리 각각에 반응하는 시스템이라면, 리액트는 도시 전체에 울리는 거대한 하나의 사이렌 소리에만 반응하는 시스템이었다.
크리스가 반박했다.
"그건 너무 비효율적이잖아요. username 하나 바뀌었다고 UI 전체를 다시 계산하는 게 어떻게 더 낫다는 거죠?"
"바로 그 지점에서 버추얼 DOM이 활약하는 겁니다." 조던이 말을 이었다. "우리는 상태 전체가 바뀌었다는 사이렌 소리를 듣고, 일단 이상적인 UI 설계도(버추얼 DOM)를 통째로 다시 그립니다. 그리고 그 설계도를 이전 설계도와 비교해서, 실제로 바뀐 부분이 '아, username 하나뿐이었구나'라는 사실을 기계적으로, 아주 빠르게 알아내는 거죠. 결국 결과는 같습니다. username 부분만 업데이트되죠."
차이점은 명확해졌다.
- 백본: 개발자가 직접 '무엇이 바뀌었을 때, 무엇을 할지'에 대한 수많은 인과관계를 코드로 정의해야 한다. (복잡성↑, 개발자 부담↑)
- 리액트: 개발자는 오직 '현재 상태가 주어졌을 때, UI는 어떤 모습이어야 하는가'만 정의하면 된다. '무엇이 바뀌었는지'에 대한 추적과 '어떻게 업데이트할지'에 대한 고민은 전부 리액트 라이브러리가 책임진다. (복잡성↓, 개발자 부담↓)
크리스는 잠시 생각에 잠겼다. 그는 자신이 백본으로 작업하며 겪었던 고통을 떠올렸다. 모델 하나에 수십 개의 listenTo가 얽혀, 도저히 그 흐름을 추적할 수 없었던 경험. 하나의 이벤트를 추가했을 때, 생각지도 못한 다른 뷰가 오작동했던 악몽.
리액트는 그 모든 복잡한 연결선을 끊어버리고, '상태 → UI'라는 단 하나의 거대하고 단순한 법칙으로 모든 것을 대체하려 하고 있었다.
"알겠습니다." 크리스가 마침내 고개를 끄덕였다. "우리는 변화의 '원인'을 추적하는 대신, 변화의 '결과'에만 집중하겠다는 거군요."
그는 비로소 깨달았다. 리액트는 단순히 데이터 변화에 반응하는 라이브러리가 아니었다. 개발자의 사고방식 자체를 '명령형'에서 '선언형'으로 바꾸어, 복잡성의 저주로부터 해방시키려는 거대한 시도였다.


