부품을 만드는 설계도, React.createClass()

462025년 09월 30일3

재사용 가능한 컴포넌트라는 개념은 팀의 모두를 흥분시켰다. 하지만 아이디어만으로는 부족했다. 이제는 개발자들이 실제로 그 ‘부품’을 쉽게 만들 수 있는 구체적인 방법을 제공해야 했다. 즉, 리액트 API의 첫 번째 핵심 함수를 설계해야 할 때였다.

“개발자들이 컴포넌트를 어떻게 정의하게 할까요?” 톰이 질문을 던졌다. “XHP처럼 PHP 클래스를 상속받게 할까요? 아니면 백본처럼 Backbone.View.extend() 같은 함수를 제공해야 할까요?”

팀원들은 각자 다른 의견을 내놓았다. 자바스크립트의 프로토타입(prototype) 상속을 직접 사용하자는 의견도 있었고, 더 단순한 팩토리 함수(Factory Function) 패턴을 선호하는 사람도 있었다.

조던 워크는 이 논쟁을 지켜보며, 자신이 생각하는 가장 중요한 원칙을 떠올렸다.

‘개발자가 리액트의 내부 구현에 대해 최대한 모르도록 해야 한다.’

만약 프로토타입 상속을 직접 사용하게 한다면, 개발자는 자바스크립트의 복잡하고 혼란스러운 this 키워드와 프로토타입 체인에 대해 깊이 이해해야만 했다. 이는 리액트를 배우는 데 큰 장벽이 될 터였다.

“우리는 개발자에게 문법적인 자유를 주는 대신, 명확한 가이드라인을 제공해야 합니다.” 조던이 자신의 의견을 밝혔다. “개발자가 그저 내용물만 채워 넣으면, 알아서 완벽한 컴포넌트 부품이 찍혀 나오는 ‘틀’을 제공하는 겁니다.”

그의 아이디어는 간단했다. 리액트는 createClass라는 단 하나의 함수를 제공한다. 개발자는 이 함수에 컴포넌트의 명세가 담긴 자바스크립트 객체를 전달하기만 하면 된다.

조던은 화이트보드에 그 모습을 그렸다.

var Avatar = React.createClass({
  // 여기에 컴포넌트의 동작을 정의하는 내용물을 채워 넣는다.
  // ...
});

React.createClass() 함수는 이 명세 객체를 받아서, 리액트가 이해할 수 있는 완전한 형태의 컴포넌트 ‘클래스(Class)’를 내부적으로 생성하여 반환해 준다. 여기서 ‘클래스’는 전통적인 의미의 클래스가 아니라, 컴포넌트를 생성하기 위한 일종의 설계도나 템플릿을 의미했다.

이 방식의 장점은 명확했다.

첫째, 단순함. 개발자는 React.createClass라는 함수 하나만 알면 된다. 복잡한 상속 구조를 고민할 필요가 없다.

둘째, 가독성. 컴포넌트의 모든 동작(render, 생명주기 메서드 등)이 하나의 객체 리터럴 안에 명시적으로 선언되므로, 코드를 읽고 이해하기 쉽다.

셋째, 자동 바인딩(Auto-binding). 조던은 이 방식의 가장 큰 장점으로 이 점을 꼽았다. React.createClass를 사용하면, 명세 안에 정의된 모든 메서드 내부의 this가 항상 해당 컴포넌트 인스턴스를 가리키도록 리액트가 자동으로 ‘묶어주는(bind)’ 작업을 해줄 수 있었다. 개발자는 더 이상 this가 가리키는 대상이 무엇인지 헷갈리지 않아도 되었다. 이것은 자바스크립트 개발자들이 겪는 가장 큰 고통 중 하나를 해결해 주는 엄청난 편의 기능이었다.

팀원들은 이 아이디어에 동의했다. React.createClass는 개발자에게는 쉬운 사용법을 제공하면서, 리액트 내부적으로는 복잡한 최적화와 관리를 수행할 수 있는 완벽한 접점이었다.

이로써 리액트의 첫 번째 공식 API가 탄생했다.
React.createClass()

이 함수는 앞으로 만들어질 수십, 수백 개의 재사용 가능한 UI 부품들을 찍어내는 공장의 기계와도 같았다. 이제 개발자들은 이 기계에 어떤 재료를 넣어야 하는지만 배우면 되었다. 그 첫 번째 재료는 바로 모든 컴포넌트의 심장, render 메서드였다.