“자, 이제 우리는 레고 블록을 만드는 방법을 알았습니다. 하지만 이 블록들은 그냥 가만히 있는 플라스틱 조각이 아닙니다. 어떤 블록들은 스스로의 의지에 따라 모습을 바꾸기도 하죠. 어떻게 그게 가능할까요?”
조던 워크는 두 번째 멘탈 모델을 설명하기 시작했다. 그는 화이트보드에 커다랗게 레고 블록 하나를 그렸다. 그리고 그 블록의 내부에 두 개의 작은 엔진을 그려 넣었다.
“모든 리액트 컴포넌트(블록)는 두 개의 심장, 즉 props와 state라는 두 개의 엔진으로 움직입니다.”
그는 첫 번째 엔진을 가리켰다.
“props 엔진은 ‘외부 동력원’입니다. 이 엔진은 컴포넌트 스스로 켤 수 없습니다. 오직 이 컴포넌트를 조립한 부모 컴포넌트만이 props라는 연료를 주입해 줄 수 있죠.”
조던은 props의 핵심 특징을 다시 한번 강조했다.
- 위에서 아래로: 동력은 언제나 부모에게서 자식으로, 한 방향으로만 전달된다.
- 읽기 전용: 자식은 부모가 준 연료를 태울 수는 있지만, 그 연료의 성분을 마음대로 바꿀 수는 없다.
props는 불변이다. - 재구성: 부모가 새로운 연료(
props)를 주입하면, 컴포넌트는 그 즉시 새로운 연료에 맞춰 다시 움직인다(리렌더링).
“많은 단순한 블록들은 이 props 엔진 하나만으로도 충분히 자신의 역할을 수행합니다. <Avatar>나 <Icon>처럼, 외부에서 주어진 정보에 따라 자신의 모습만 보여주면 되는 블록들이죠. 우리는 이런 블록들을 ‘상태 없는(Stateless)’ 컴포넌트라고 부릅니다.”
이어서 그는 두 번째 엔진을 가리켰다.
“하지만 어떤 블록들은 더 복잡한 임무를 수행해야 합니다. 외부 동력원뿐만 아니라, 스스로 에너지를 만들고 소비하는 ‘내부 발전기’가 필요하죠. 이 내부 발전기가 바로 state 엔진입니다.”
조던은 state의 특징을 props와 비교하며 설명했다.
- 내부 소유: 이 발전기는 컴포넌트가 태어날 때(
getInitialState)부터 내부에 장착되어 있습니다. 외부에서는 이 발전기의 존재조차 알 수 없죠. 완벽하게 캡슐화되어 있습니다. - 자기 제어: 컴포넌트는
setState라는 유일한 스위치를 통해, 스스로 이 발전기를 켜고 끌 수 있습니다.state의 변경은 오직 컴포넌트 자신의 책임입니다. - 시간의 기록: 이 발전기는 컴포넌트가 살아오면서 겪은 모든 변화를 기록합니다. 사용자의 입력, 시간의 흐름, 서버와의 통신 결과 등.
state는 컴포넌트의 ‘기억’입니다.
“<CommentBox>나 <Clock> 같은 복잡한 블록들은 이 state 엔진을 가집니다. 그들은 부모가 준 연료(props)를 사용함과 동시에, 스스로 만든 에너지(state)를 이용해 더욱 역동적으로 움직입니다. 우리는 이런 블록들을 ‘상태 있는(Stateful)’ 컴포넌트라고 부르죠.”
이 두 개의 엔진이라는 비유는 props와 state의 역할 분담을 완벽하게 설명했다.
개발자가 어떤 데이터를 마주했을 때, 더 이상 혼란스러워할 필요가 없었다.
‘이 데이터는 외부에서 주입되는 연료인가? → props’
‘이 데이터는 블록 스스로가 만들어내고 관리하는 에너지인가? → state’
“리액트 개발의 핵심은, 이 두 엔진을 올바르게 이해하고 사용하는 것입니다.” 조던이 결론지었다. “가능한 한 많은 블록들을 props 엔진만 가진 단순한 형태로 만들고, 꼭 필요한 소수의 블록에만 강력한 state 발전기를 장착하는 것. 이것이 바로 우리가 복잡성을 관리하는 방식입니다.”
이제 팀원들은 리액트 컴포넌트의 내부 구조를 꿰뚫어 보게 되었다. 모든 컴포넌트는 두 개의 심장을 가지고 있으며, 이 심장 박동의 조화가 UI 전체를 살아 숨 쉬게 만든다는 것을. 그들의 다음 질문은 명확했다.
‘이 두 개의 엔진, 특히 state 발전기를 켜는 유일한 스위치는 대체 어떻게 작동하는가?’


