React Nativeとはどんな開発ツールなのか
本連載では、React Nativeについて解説していきます。React Nativeは、Facebook社が中心になって開発が進められている、オープンソースのクロスプラットフォーム開発ツールです。
Reactといえば、これもFacebook社がオープンソースで開発している、JavaScript向けのUI状態管理ライブラリです。その名を受け継いだReact Nativeは、Reactを活用してモバイルアプリを開発するためのツールになっています。React Nativeの主な特徴としては、次の3つが挙げられます。
- JavaScript言語とReactでUIの状態管理を記述できる
- Android SDKやiOS SDKが提供するビュー(ネイティブビュー)を内部実装として持つ、React向けの画面部品(コンポーネント)が利用できる
- JavaScriptCoreとBabelにより、ブラウザと遜色ないJavaScript実行環境が提供されている
それぞれの特徴について、解説していきます。
JavaScript言語とReactでUIの状態管理を記述できる
React Nativeでは、ブラウザ向けにJavaScriptとReactによるシングルページアプリケーションの開発を行う場合と近い感覚で、モバイルアプリの開発を行えます。そのため、Reactの経験があれば、比較的導入しやすいツールになっているといえるでしょう。実際の例を挙げてみます(リスト1)。
import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; // HTMLのようなマークアップでレイアウトの構造を定義する const App = (props) => ( <View style={styles.container}> <Text>Hello, React Native!</Text> </View> ); export default App; // CSSライクな指定でスタイルを定義する const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, });
ECMAScript 2015相当の言語仕様で書かれたJavaScriptに、Reactの特徴であるHTMLライクな記法「JSX」によるレイアウトが記述された、標準的なReactによる画面部品の実装になっています。リスト1をReact Nativeの画面として記述して実行すると、AndroidとiOSで、それぞれ図2の通りに画面が表示されます。
画面を表示するのに必要なコードがリスト1のような短いもので済むのは、モバイルアプリの経験がある方からすると、驚くことかもしれません。詳しい解説は次回以降に譲りますが、Reactを活用することで、複雑な状態管理にも耐えうる堅牢なUIを実装できます。
ネイティブな画面部品
JavaScriptで記述したHTMLライクなレイアウトが、実際に画面に表示されるわけなので、「これは、ブラウザをアプリ内に組み込む仕組みであるWebViewを利用しているのではないか」と考える方も多いと思います。
しかし、それは違います。React Nativeが「ネイティブ」の名を冠しているのは、UIの描画をWebViewに任せずに、Android SDKやiOS SDKが提供している「本来の」画面部品を使って画面を構築していることに由来しています。
例えば、リスト1でレイアウトの記述に利用した、<View>
と<Text>
の画面部品がありました。これらはそれぞれ、実行時にJavaScriptからAndroid SDKやiOS SDKへと、UIの描画を依頼します。その結果、<View>
要素はAndroid SDKのandroid.view.View
やiOS SDKのUIKitが持つUIView
に変換されますし、<Text>
要素も同様にandroid.widget.TextView
やUIView
へと変換されます(図3)。
iOSアプリ開発の経験がある方は「あ、<Text>
は UILabel
じゃないんだ」と思われたかもしれません。これは<Text>
要素はネストができるという特殊な事情により、こういった実装になっていると思われます。
このように、JavaScript側で定義したレイアウトは、すべてネイティブなビューに変換されて描画されます。この特徴によって、カメラのプレビューなどのブラウザでは困難だったビューも描画することができ、ブラウザ製アプリに対する大きなアドバンテージになっています。
JavaScript実行環境はブラウザに準拠
ブラウザを使っていないのはわかりましたが、となると、独自のJavaScript処理系を積んでいるのでしょうか。いつも使っている、あのグローバル関数は使えるのでしょうか。普段からJavaScriptの多様性につらい思いをしているWebフロントエンドエンジニア諸氏が、一番気になっているところでしょう。次の3つの観点で見ていきましょう。
- JavaScript(ES5)を解釈する
- ES201xを解釈する
- 組み込み関数の実装を提供する
まず、現代のブラウザ向け開発で最低限の言語仕様となっているECMAScript 5(ES5)への対応の観点です。これについては、特に問題ありません。React Nativeは、JavaScriptを実行する際に、SafariのエンジンであるWebKitの、さらに一部であるJavaScriptCoreを、JavaScriptを解釈するためのライブラリとして利用します。
iOS SDKでは、JavaScriptCoreが標準ライブラリとして提供されており、それを使う形になるので、事実上、Safariと同等の文法が解釈できることになります。Android向けには、JavaScriptCoreをC++ライブラリとしてポーティングしたものが使われています。こちらはAndroidから見てサードパーティのライブラリになるため、更新が遅くなりがちです。今後の改善に期待したいところです。
次に、最新のブラウザ向け開発における言語仕様となっている、ECMAScript 201xへの対応の観点です。これについては、JavaScriptのコンパイラであるBabelがビルドツールに組み込まれています。JavaScriptCoreが読み込める言語仕様まで、ソースコードをBabelがダウングレードしてくれるので、プログラマーは気兼ねなく新しいバージョンのJavaScriptを記述することができます。React Native向けのBabelのプリセットで提供される、言語仕様については、こちらの公式ページを参照してください。
最後に、ブラウザが提供してくれていた組み込み関数は、React Nativeにもあるのかという観点です。基本的にはMDNのJavaScriptリファレンスで紹介されているような、Web標準のAPIで実装されています。ただし、ブラウザと同じように、React Nativeでも未実装のものがありますので、適宜、Polyfillな(代替実装の)ライブラリを用意する必要があることにはご留意ください。言語仕様の話題で紹介した公式ページに、実装されている標準ライブラリの一覧がありますので、実装状況の確認はこちらを参照してください。
[コラム]組み込み関数の内部実装もネイティブ
これに関連した、React Nativeの面白い点として、ネイティブブリッジという仕組みがあります。これにより、JavaScriptの関数の内部実装を、ネイティブ、つまりAndroid SDKやiOS SDKで持つことができるのです。setTimeout
やsetInterval
なら、JavaやObjective-Cで記述されたタイマー実装がされています。また、XMLHttpRequest
も、Android SDKやiOS SDKにおける標準的なネットワーク実装になっています(React Nativeではfetch
はXMLHttpRequest
のラッパーという扱いです)。
ただし、こういった関数の内部実装がJavaScript製でないことは、特別なことではありません。Google ChromeのDevToolsでコンソールを開き、関数の名前を直接打ち込んで、エンターキーを押してみてください。
関数の実装が[native code]
といった表記になっています。これは、ブラウザの標準関数も、JavaScriptではない言語(C++など)で記述されていることを表しています。こういった面からも、React NativeがWebの文化に寄り添おうと心がけていることが垣間見えますね。