리액트의 첫 번째 심장, render() 함수

432025년 09월 27일3

"자, 그럼 이제부터 우리가 만들 API의 모습을 구체적으로 그려봅시다."

톰의 말에 팀원들은 모두 화이트보드로 시선을 모았다. 리액트라는 이름과 철학은 정해졌다. 이제는 개발자들이 실제로 사용하게 될 코드의 모습을 디자인해야 할 차례였다. 가장 먼저 정의해야 할 것은 리액트의 가장 핵심적인 부분, 바로 UI를 선언하는 함수였다.

프로토타입 단계에서는 CounterComponent(props)처럼 일반적인 자바스크립트 함수를 사용했다. 하지만 팀은 이 방식만으로는 부족하다는 결론을 내렸다. 페이스북처럼 복잡한 애플리케이션에서는 UI 조각이 단순히 데이터를 받아 화면을 그리는 것 이상의 역할을 해야 했다.

  • 컴포넌트가 처음 화면에 나타났을 때, 서버에서 데이터를 가져와야 할 수도 있다.
  • 컴포넌트가 화면에서 사라질 때, 점유하고 있던 메모리나 이벤트 리스너를 정리해야 한다.
  • 컴포넌트 스스로가 시간이 지남에 따라 변하는 내부적인 상태를 가져야 할 수도 있다.

이 모든 것을 일반적인 함수 하나에 담는 것은 코드를 지저분하게 만들고 리액트의 철학을 해칠 우려가 있었다.

"우리에게는 좀 더 체계적인 구조가 필요합니다." 조던이 말했다. "단순한 함수가 아니라, 컴포넌트의 동작을 정의하는 명세서 같은 것이죠. 그리고 그 명세서의 가장 중요한 심장은, 무엇을 그릴지를 알려주는 함수가 될 겁니다."

팀은 수많은 논의 끝에, 모든 리액트 컴포넌트는 반드시 render라는 이름의 메서드를 가져야 한다는 규칙을 세웠다.

render()

이 이름은 직관적이었다. ‘그리다’, ‘표현하다’는 뜻 그대로, 이 메서드의 역할은 오직 하나였다. 현재 컴포넌트의 상태를 기반으로, 화면에 그려질 버추얼 DOM 객체를 반환하는 것.

중요한 것은 render 메서드에 부여된 엄격한 제약사항이었다.

render 메서드는 반드시 순수해야(Pure) 합니다.” 조던이 강조했다. “이 안에서 외부 상태를 바꾸거나, DOM을 직접 조작하거나, 서버에 데이터를 요청하는 등의 부작용(Side Effect)을 일으키는 코드는 절대로 들어가선 안 됩니다. 오직 주어진 데이터를 바탕으로 계산하고, 버추얼 DOM을 반환하는 역할에만 충실해야 합니다.”

이 제약은 리액트의 예측 가능성을 보장하는 핵심적인 장치였다. 리액트는 render 메서드가 순수하다고 ‘믿기’ 때문에, 안심하고 이 메서드를 수시로 호출하여 버추얼 DOM을 비교할 수 있었다. 만약 render가 호출될 때마다 다른 일을 한다면, 전체 시스템의 신뢰가 무너지는 것이었다.

맷이 질문을 던졌다.
“알겠습니다. render는 순수해야 한다. 그럼 서버에서 데이터를 가져오는 것 같은 ‘순수하지 않은’ 작업들은 전부 어디서 처리해야 하죠?”

“훌륭한 질문입니다.” 조던이 대답했다. “그것이 바로 우리가 render 외에 다른 메서드들을 정의해야 하는 이유입니다. 컴포넌트의 ‘생명주기(Lifecycle)’에 맞춰 적절한 시점에 호출될 특별한 메서드들이죠.”

render 메서드의 탄생은 리액트 컴포넌트의 기본 골격이 완성되었음을 의미했다. 모든 컴포넌트는 이제 하나의 심장, 즉 render를 가지게 되었다. 이 심장은 외부의 어떤 자극에도 흔들리지 않고, 오직 자신의 상태만을 보고 묵묵히 UI의 설계도를 펌핑해낼 것이다.

그리고 이 심장 주위로, 컴포넌트의 탄생과 성장, 소멸을 관장할 다양한 생명주기 메서드들이 하나씩 혈관처럼 연결되기 시작할 터였다. 리액트라는 작은 생명체가 마침내 구체적인 형상을 갖추기 시작한 순간이었다.