ReactJS 둘러보기 - XHP부터 React Native까지

페이스북이 지난 1월 28일, 29일 양일간 열린 ReactConf 2015에서 React Native라는 기술을 발표했다. 흥미로운 기술이지만 이에 대해서는 잠시 뒤에 알아보기로 하고 이 글에서는 먼저 React Native의 기반이 된 ReactJS 자체에 대해 살펴볼까 한다. ReactJS의 역사는 XHP로 거슬러 올라간다.

XHP

잘 알려진대로 페이스북은 PHP를 사용한다. 어느 정도로 열심히 사용하냐면 PHP 자체의 성능을 개선하기 위해 PHP를 C++로 컴파일한 후 빌드하는 Hiphop for PHP라는 프로젝트로 진행했었고(현재는 HHVM으로 대체된 상태), PHP 엔진 자체를 수정한 HHVM도 발표했을 정도이다. 그렇다고 PHP라는 언어 자체에 대한 고민이 없었던 것도 아니다. 아예 PHP의 문법 개선판 같은 Hack이라는 언어도 내놓을 정도이다. PHP라는 언어의 문법 구조를 바꾸려는 노력이 하나 더 있었는데 바로 2010년에 발표한 XHP가 그것이다.

로고가 다소 성의없어 보이는 건 기분 탓이다.
로고가 다소 성의없어 보이는 건 기분 탓이다.

여전히 진행 중인 이 프로젝트는 특히 HTML 출력이 많은 PHP 언어의 특성에 맞춰 XML 또는 HTML을 더 빠르고 편하게 출력할 수 있도록 하는 것이 목적이었다. 예를 들어 다음 코드를 살펴보자.

<?php
if ($_POST['name']) {
?>
    <span>Hello, <?=$_POST['name']?>.</span>
<?php
} else {
?>
    <form method="post">
    What is your name?<br>
    <input type="text" name="name">
    <input type="submit">
    </form>
<?php
}

PHP에서 HTML 문자열을 출력하려면 ?>로 닫고 <?php로 열고 다시 ?>로 닫는 귀찮은 과정을 거쳐야 한다. 코드가 지저분해지고 읽기 어려워지는 것은 물론이다. 그렇다고 echo 명령을 사용하자니 문자열 이스케이프, 계산식 삽입의 어려움 등으로 인해 더 나빠지면 나빠졌지 나아질 것이 없다. 이 때 XHP를 사용하면 간단히 echo 명령을 사용해 HTML을 출력할 수 있다. 심지어 따옴표로 묶을 필요조차 없다.

<?php
// Note: include 코드 생략됨
if ($_POST['name']) {
  echo <span>Hello, {$_POST['name']}</span>;
} else {
  echo
    <form method="post">
      What is your name?<br />
      <input type="text" name="name" />
      <input type="submit" />
    </form>;
}

또한 다음과 같이 간단하게 변수에 DOM 객체를 담을 수도 있다.

<?php
$div = <div />;
$div->appendChild($foo);

그 뿐이 아니다. 원한다면 다음과 같이 다소 생소한 문법을 사용해 커스텀 태그를 작성할 수도 있다.

<?php
// <fb:thing> 태그 작성
function :fb:thing extends :x:element {
  protected function render() {
    return <div class="thing">thing</div>;
  }
}

즉, XHP를 사용하면 귀찮은 DOM 코딩이 다소 편해지는데다가 서버측에서 DOM 컴포넌트를 만들어 사용할 수 있다.

ReactJS

페이스북 엔지니어들은 아마 이 아이디어가 굉장히 마음에 들었나보다. XHP를 브라우저로 옮기려는 시도를 했고, 그게 바로 2013년 6월에 발표한 ReactJS가 되었다[ref]ReactJS는 XHP에서 왔다고 알려져 있으나 보기에 따라서는 지금은 사라져버린 비운의 기술(?) E4X와도 많이 닮아있다. Mozilla E4X Tutorial 참고[/ref]. ReactJS(JS를 빼고 React라고 부르기도 한다)는 JSX라는 자바스크립트의 확장 문법을 통해 XHP와 유사한 기능을 제공하고 있다. 간단히 다음 코드를 보면 어렵지 않게 이해가 될 것이다.

<body>
    <div id="example"></div>
    <script type="text/jsx">
      React.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>

커스텀 태그를 만들 수 있는 기능도 빼놓지 않았다. React.createClass 문법을 사용하면 새로운 태그를 작성해서 사용할 수 있다.

var CheckLink = React.createClass({
  render: function() {
    return <a {...this.props}>{'√ '}{this.props.children}</a>;
  }
});

React.render(
  <CheckLink href="/checked.html">
    Click here!
  </CheckLink>,
  document.getElementById('example')
);

이 밖에도 React는 변경된 부분만 업데이트하여 속도를 향상시키는 Virtual DOM 기능, 이해하기 쉬운 단방향 데이터 바이딩 기능 등을 제공하고 있다. 이런 기능을 지원하는 React의 컨셉은 단순하다. 흔히 사용되는 MVC 패턴에서 View에만 집중하겠다는 것이다.

React는 AngularJS 또는 BackboneJS와 비교되는 경우가 많지만 다른 프레임워크들이 MVC를 모두 다루겠다는 목표를 가진 것에 비해 React는 View에만 집중하고 있다. 특히 커스텀 엘리먼트를 만들 수 있다는 것이 가장 큰 특징이므로 W3C의 웹 컴포넌트(web component) 또는 이를 구현한 폴리필(polyfill)[ref]브라우저에 아직 내장되지 않은 기능을 구현해주는 코드를 가리켜 폴리필이라 부른다. 구식 IE에서 HTML5 엘리먼트를 사용할 수 있게 하는 html5shiv를 예로 들 수 있다.[/ref] 라이브러리인 Polymer와 비교하는 것이 더 적합할 것이다. 그런데 정말 그럴까?

XHP가 발표되던 2010년과 React가 발표되던 시기인 2013년 사이에 있었던 웹의 큰 변화로는 NodeJS의 등장과 확산으로 볼 수 있다. NodeJS가 처음 출시된 시기는 2009년이었지만 2011년에 npm이 추가되고 Windows 운영체제를 지원하면서 진정한 멀티플랫폼 도구가 되었으며 실제 서비스에도 NodeJS가 널리 사용되기 시작했다. LinkedIn이라는 큰 서비스에서 NodeJS를 도입하기 시작한 것도 이 때였다. React는 이 점을 적극 활용했다.

React에 대해 더 말하기 전에 잠시 다른 라이브러리 얘기를 해보자.

AngularJS, Ember.js 등 자바스크립트 프레임워크는 단순히 서버를 보조하던 역할에서 벗어나 해시나 HTML5 History API를 통해 각 상태별 고유 주소도 구현하고 있다. 클라이언트 라이브러리가 페이지 렌더링에 대한 책임을 가지고 있다보니 예전과 다른 문제가 발생했는데 첫 번째로는 검색 엔진 최적화 문제를 들 수 있다. 검색 엔진은 자바스크립트를 실행할 수 없기 때문에[ref]단, 구글 수집 로봇은 자바스크립트도 실행한다고 한다.[/ref] 검색 엔진에서 콘텐츠를 찾지 못할 수 있다. 두 번째로는 성능 문제를 들 수 있다. 서버에서 HTML 코드를 전부 만들어서 보내주는 것이 아니기 때문에 사용자가 해당 페이지에 최초 접속시 클라이언트 라이브러리가 필요한 데이터를 서버에 요청하고 가져와서 렌더링하는 시간이 필요하다. 따라서 사용자에게는 서버에서 HTML 코드를 전부 만들어서 보낼 때보다 더 느리게 느껴질 것이다.

이를 해결하기 위해 등장한 개념이 바로 동형(同刑) 자바스크립트(Isomorphic JavaScript)이다. 2013년에 널리 알려지기 시작한 이 용어는[ref]정확히는 Nodejitsu의 Charlie Robbins가 2011년에 쓴 Scaling Isomorphic JavaScript Code라는 글에서 처음 등장했지만, AirBNB의 Spike Brehm이 Isomorphic JavaScript: The Future of Web Apps라는 글을 쓰며 유명해졌다. http://isomorphic.net/에서는 동형 자바스크립트에 대한 소식과 이 개념을 따르는 라이브러리를 볼 수 있다.[/ref] 간단히 말해 클라이언트와 서버가 같은 언어를 사용한다는 점을 십분 활용하여 서버와 클라이언트가 같은 코드를 공유한다는 뜻이다. 덕분에 원한다면 서버에서도 클라이언트와 같은 HTML 결과물을 만들어 낼 수 있게 되었고, 폼에서 전달되는 데이터에 대해서도 같은 코드를 사용해 유효성 검사를 할 수 있게 되었다.

다시 React로 돌아오면, React는 처음 만들어 질 때부터 서버-클라이언트 양쪽에서 사용할 수 있는 라이브러리임을 표방했다. 클라이언트에서 만들어 내는 결과물을 서버에서도 만들어 사용자에게 전송할 수 있다는 것이다. 애초에 React는 서버측 라이브러리인 XHP를 클라이언트로 옮기려는 시도였으므로 어찌 보면 이런 시도가 당연할 지도 모른다. 이렇게 React에서 제공하는 View는 클라이언트를 넘어 서버까지 영역을 확장했다[ref]자바스크립트가 아닌 Ruby, Python, .NET 등을 위한 JSX 컴파일러도 있다. 자세한 내용은 https://github.com/reactjs을 참고하자.[/ref]. 참고로 Netflix 역시 이 같은 장점때문에 최근 React를 도입한 바 있다("Netflix likes React" 참고).

React Native

2015년 1월 28일과 29일에 열린 React.js Conf 2015에서 내 관심을 사로 잡은 기술이 있었는데 바로 React Native였다. 이전에도 자바스크립트를 사용해 모바일 앱을 개발하겠다는 시도는 많았지만 Titanium을 제외하고는 대부분 Webview를 활용한, 즉 네이티브와는 거리가 있는 기술 뿐이었다. 상대적으로 단순한 앱 정도는 만들 수 있을지 모르나 네이티브의 이득을 얻을 수 없거나 사용이 어렵다는 점 때문에 대부분은 내 관심에서는 멀어져 있었다. 그런데 React Native는 달랐다.


React Native는 Webview를 사용하지 않는다. 대신 백그라운드 쓰레드에서 자바스크립트를 실행하며 네이티브 컴포넌트의 레이아웃을 다루게 되는데, 이 때 느린 자바스크립트가 UI 성능의 병목이 되는 것을 방지하기 위해 UI를 다루는 메인 쓰레드와 비동기로 통신한다.
느린 자바스크립트는 UI 성능에 병목 현상을 일으킬 수 있다.
느린 자바스크립트는 UI 성능에 병목 현상을 일으킬 수 있다.

React Native는 비동기 통신과 배치 작업을 통해 문제를 해결했다.
React Native는 비동기 통신과 배치 작업을 통해 문제를 해결했다.

React Native에서 가장 인상적인 부분은 역시 ReactJS를 그대로 모바일로 가져와 사용한다는 점이다. 다른 점이 있다면 태그에 HTML 엘리먼트 이름 대신 네이티브 컴포넌트 이름을 사용한다는 점이다. 다음 예제를 살펴보자.

var MoviesApp = React.createClass({
  render : function() {
    return (
      <NavigatorIOS
        style={styles.container}
        initialRoute={{title: 'Movies', components: <SearchScreen />}}
        routeMapper={MoviesRouteMapper}
      />
    );
  }
});

여기서 알 수 있는 두 가지 사실은 1. 웹에서 사용하던 React와 거의 비슷한 형태를 취하고 있다는 것과 2. iOS의 네이티브 컴포넌트를 그대로 사용하고 있다는 것이다. 앞서 잠깐 언급한 Titanium도 그렇지만 웹 기술로 모바일 앱을 만들 수 있다고 나선 프레임워크 대부분은 한 번 작성하고 나면 iOS든 Android든 똑같은 코드를 적용할 수 있다는 이른바 "Write once, run anywhere"를 기치로 내세운다. 그런데 React의 접근 방식은 다르다. 한 번 React를 배우고 나면 클라이언트에도 서버에도 그리고 모바일 앱에도 사용할 수 있다는 "Learn Once, write anywhere"을 특징으로 한다.
learn_once_write_anywhere
<View>, <Text>, <Image> 등 일부 공통 컴포넌트가 있기는 하지만 기본적으로 React는 네이티브 컴포넌트를 그대로 가져온다는 것을 컨셉으로 하고 있다. 모든 플랫폼에 항상 똑같은 컴포넌트를 제공해준다는 것은 불가능하기도 하거니와 제공된다해도 공통적이지 않은 네이티브 컴포넌트의 기능에 제약을 두어야 한다. 따라서 이처럼 아예 네이티브 컴포넌트로 접근하게 만든 전략은 여러 플랫폼을 지원해야 하는 라이브러리로서 좋은 선택일 수 있다.

HTML 엘리먼트에 대응해서 네이티브 컴포넌트를 사용했다면 CSS처럼 컴포넌트를 스타일링하는 기술도 있어야 할 것이다. 네이티브 레이아웃 방식보다 (몇 가지 단점을 제외하면) CSS가 훨씬 낫다고 생각한 React 개발팀은 아예 네이티브 컴포넌트도 CSS를 사용해 꾸밀 수 있도록 만들었다.

var styles = StyleSheet.create({
  textContainer: {
    flex: 1,
  },
  movieTitle: {
    flex: 1,
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 2,
    textAlign: 'center'
  },
  ...
});

"만들었다"라고 표현했지만 사실 이 역시 새로운 기술이 아니라 이미 예전에 공개했던 기술을 재사용한 것이다. CSS를 사용해 앱의 레이아웃을 만든다는 발상 자체는 새롭지 않지만, 네이티브 앱에 자연스럽게 녹아들게 만들었다는 점이 어쩌면 웹 개발과 마찬가지로 모바일 앱도 언젠가 프론트엔드 개발자와 백엔드 개발자가 나누어 질지도 모르겠다고 생각하게 만들었다.

React Native에는 그 밖에도 매력적인 요소가 많다. 구글 크롬을 이용한 디버깅, 실시간 코드 반영 등 그 밖의 자세한 내용은 다음 동영상을 참고하자.

마치며

React를 보고 처음에는 View만 담당하는, 바꿔 말하면 다른 프레임워크에 비해 다소 불완전한 클라이언트 라이브러리라고 생각했다. 그래서 크게 관심을 두지 않았던 프로젝트였는데 어느샌가 플랫폼을 확장하더니 오늘에 이르러서는 배워야 할 이유가 가장 많아진 라이브러리가 되었다.

React Native는 오픈소스 프로젝트이지만 현재는 컨퍼런스에 참석한 사람에게만 저장소가 공개되어 있다. SNS를 통해 전해지는 소식을 보면 이 기술 혹은 새로운 장난감을 빨리 접해보고 싶다는 생각이 앞선다. React Native가 프론트엔드 개발자에게 새로운 기회가 되어줄지는 잘 모르겠지만, 많은 사람들을 흥분시킬만한 매력이 있는 것은 확실한 듯 하다. 트위터에 올라온 몇 가지 반응을 소개하며 글을 마친다.

(순서대로)
"React Native로 게임 UI 만들기 너무 쉽잖아. Cmd+R을 누르면 UI가 새로고침 되고." - James “Jimmy” Long
"React Native 덕분에 지금부터는 iOS 개발자." - Ryan Florence
"좋아, @reactjs. 오랫동안 버텼는데 결국 이제는 관심이 생겼어." - Dan Webb
"아니, 진짜로. 말도 안되잖아 이거." - John Goering ن
"나 지금 react-native 만져보고 있는데 우와 ㅅㅂ" - Joey Yang

[adsense]

  1. 어제 발표 잘 들었습니다. 🙂 제일 인상적인 세션이었습니다.
    Native javascript 보다 빠른 경우도 있다는 점이 놀라웠는데요.
    Ember, Angular, React 성능 비교 동영상을 보여주셨는데 혹시 링크 공유해 주실 수 있나요?

댓글을 남겨주세요

This site uses Akismet to reduce spam. Learn how your comment data is processed.