render() 메서드라는 심장을 갖추게 되자, 팀의 논의는 자연스럽게 그 심장을 품고 있는 몸체, 즉 ‘컴포넌트(Component)’ 자체의 정의로 옮겨갔다.
“그래서, 우리의 ‘컴포넌트’는 정확히 무엇입니까?”
톰이 화이트보드에 ‘Component’라고 크게 쓰며 질문을 던졌다. “백본의 View와는 어떻게 다른 거죠?”
그 질문에 백본 전문가였던 크리스가 자신의 생각을 밝혔다.
“백본의 View도 재사용이 가능합니다. render 함수와 비슷한 template을 가질 수 있고, 특정 모델에 묶여 독립적으로 작동하죠. 우리가 만들려는 컴포넌트가 그것과 본질적으로 다른 점이 무엇인지 명확해야 합니다.”
일리 있는 지적이었다. 만약 리액트 컴포넌트가 단순히 백본 뷰의 다른 이름에 불과하다면, 이 모든 노력은 의미가 퇴색될 터였다.
조던 워크가 앞으로 나섰다.
“둘은 뿌리부터 다릅니다. 백본의 View는 이미 존재하는 DOM의 특정 영역을 ‘제어’하는 관리자에 가깝습니다. el: '#my-app'처럼, 자신의 영토를 먼저 선언하고 그 안에서 일어나는 일을 책임지죠.”
그는 말을 이었다.
“하지만 리액트 컴포넌트는 DOM을 제어하는 관리자가 아닙니다. 컴포넌트는 UI 조각 그 자체를 생성하는 ‘설계도’이자 ‘독립된 부품’입니다.”
조던은 ‘좋아요’ 버튼을 예로 들었다.
“과거에 ‘좋아요’ 버튼은 그저 특정 클래스 이름을 가진 HTML 태그에 불과했습니다. 하지만 리액트의 세계에서 LikeButton은 고유한 부품이 됩니다. 이 부품 안에는, 자신이 화면에 어떻게 보여야 하는지에 대한 시각 정보(render가 반환하는 버추얼 DOM)와, 클릭되었을 때 어떻게 동작해야 하는지에 대한 로직이 모두 하나로 묶여 캡슐화됩니다.”
이 ‘캡슐화’라는 단어에 팀원들의 눈빛이 흔들렸다. 그들이 스파게티 코드에서 가장 고통받았던 부분이 바로 이것, 관심사의 분리가 제대로 되지 않았던 문제였기 때문이다.
“더 중요한 것은 ‘조립(Composition)’입니다.”
조던은 화이트보드에 컴포넌트들의 관계를 그리기 시작했다.
“<Post>라는 거대한 컴포넌트는, <AuthorProfile>, <PostContent>, <ActionBar>라는 더 작은 부품들을 조립해서 만들어집니다. 그리고 <ActionBar> 부품은 다시 <LikeButton>, <CommentButton>, <ShareButton>이라는 아주 작은 부품들을 조립해서 만들어지죠.”
그림은 명확했다. 거대한 UI가 레고 블록처럼, 더 작은 블록들의 조합으로 이루어지는 모습이었다. 각각의 블록은 자신의 역할 외에는 아무것도 알 필요가 없었다. <LikeButton>은 자신이 <Post> 안에 있는지, 아니면 <PhotoViewer> 안에 있는지 전혀 신경 쓰지 않는다. 그저 주어진 데이터에 따라 자신의 모습을 그리고, 자신의 로직을 수행할 뿐이다.
맷은 그 그림을 보며 깊은 깨달음을 얻었다.
“그렇다면… 저는 이제 ‘좋아요’ 버튼을 만들 때, 페이스북의 다른 어떤 부분도 신경 쓸 필요가 없다는 거군요. 그냥 완벽하게 독립된 LikeButton 부품 하나를 만드는 데만 집중하면, 그 부품은 어디서든 제가 의도한 대로 정확하게 작동하겠네요.”
그의 말에 조던이 미소를 지으며 고개를 끄덕였다.
“바로 그겁니다. 복잡한 전체 시스템을 생각하는 대신, 작고 단순하며 독립적인 부품에만 집중하는 것. 그것이 리액트가 복잡성을 정복하는 방식입니다.”
컴포넌트.
그것은 단순히 UI를 그리는 함수가 아니었다. 로직과 뷰를 하나로 묶어 외부로부터 완벽하게 격리시킨, 재사용과 조립이 가능한 독립된 부품.
리액트라는 거대한 기계를 움직일 가장 기본적인 단위가 마침내 정의된 순간이었다. 이제 남은 것은, 이 부품을 생산할 ‘공장’을 짓는 일이었다.


