ナカザンドットネット

Android Developer's memo

React NativeをWebに持ってくることの意味

React Native for Webは、React NativeをWebに持ち込む試みです。

しばしば、こういった試みに対して「わけがわからない」「本末転倒である」といった意見を見かけますが、筆者は妥当な試みであるという印象を持っています。ちょっと頭の中にあるものを出してみようと思います。

ブラウザはGUIアプリケーションプラットフォームではない

まず前提となっている思想として、 WebブラウザはGUIアプリケーションプラットフォームではない 、というものがあります。ブラウザは元々ドキュメントビューアであり、Webページで情報を閲覧するためのソフトウェアであり、アプリケーションのランタイムではなかった、という立場です。

HTMLもCSSもJS(vanilla jsね)も、綺麗でセマンティックでインタラクティブなWebサイトを作るための進化を遂げましたが、元々がドキュメントビューアなので、アプリを動かすためのフレームワークとしては無理が残ります。

巨大な配列データのリストを省メモリで表示できる仕組み、ユーザーの言語や地域の設定に合わせて自動で表示言語を切り替える機能など、AndroidやiOSであれば当然持っている機能はブラウザには搭載されていません。ダウンロード処理や非同期処理を伴うならばぜひ使いたいプログレスバーも、インジケータ(ぐるぐる)も、標準では搭載されていません。

ブラウザで同じようなことをしたいと思ったら、人気っぽいJavaScriptライブラリやCSSフレームワークを選定し、導入する必要があります。これは「ドキュメントビューアを頑張ってGUIアプリケーションっぽく動かすための作業」です。頑張りの大半をライブラリ製作者が担ってくれているために実感しづらいですが、筆者はそう思っています。

これはブラウザがGUIアプリケーションプラットフォームとして劣っているという話をしたいのではなく、そもそもドキュメントビューアなので、GUIアプリケーションが作りづらいのは自然なことである、という話です。divもspanもul/liも、それらを装飾するCSSも、GUIのレイアウトを組むことに特化した作りをしているわけではないのです。

Flexboxについて

ちょっと主張がブレるように思われるかもしれませんが、Flexboxはアプリ開発に向いているなあ、と思っています。Webサイトを作っていく上でも役立つので、別にアプリ開発のために作られた機能というわけでもないと思うのですが、AndroidのLinearLayoutやiOSのStackViewなど、類似の機能がアプリ開発の現場では欠かせない状況になっているので、これが登場したときには本当に嬉しかった・・・

React DOMはGUIアプリケーションフレームワークではない

ブラウザそのものがGUIアプリケーションプラットフォームでないのであれば、何らかのフレームワークを噛ませることで、ある程度GUIアプリケーションを作りやすくなりそうですよね。筆者はしばらくの間、「React DOMを使ったらブラウザをGUIアプリケーションプラットフォームであるかのように扱える」と思っていました。

さて、現実を見てみましょう。

Reactは、DOMをいくらかの単位で切り分け、コンポーネントとして扱わせてくれます。Reactは、データの更新に対するDOMの更新を最低限に抑えてくれます。Reactのおかげで、複雑なインタラクションを最低限のコストで管理できるようになりました。

これで、どんな複雑なWebサイトでも構築できます!

…………………………

……………………

…………

……やっぱりGUIアプリケーションのフレームワークという感じではないぞ……?

「ドキュメントビューアを頑張ってGUIアプリケーションっぽく動かす」ためのコストを下げてくれる存在であることは間違いないのですが、レイアウトを組むために必要な頑張りの方向性は、楽になっただけで(これはこれでもちろん重要なんですが)、あまり変わっていません。

React NativeはGUIアプリケーションプラットフォームの抽象である

AndroidやiOSはGUIアプリケーションプラットフォームです。React Nativeは両者の上でGUIアプリケーションを構築させるためのツールを用意するにあたり、AndroidやiOSにあったものを共通化する形で「GUIアプリケーションを作るなら大抵こういうのが必要でしょ」というコンポーネント群やモジュール群を用意しました。

特にコンポーネント群には嬉しいものが多いです。基本となるViewText以外にも、ぐるぐるを出してくれるActivityIndicatorや、巨大な配列データを省メモリでリスト表示できるFlatList、挟めばスクロールさせてくれるScrollView、進捗を表示するProgressBar/ProgressView、引っ張って更新のRefreshControlなど、 「無きゃ無いでどこかから調達してくるなり自作なりするけど、あるなら嬉しい」 が揃っています。もちろん足りないものもあるので自作することもありますが、GUIアプリケーションを構築していくにあたっての最低限のベースとしては充実していると思います。

この抽象はAndroid/iOSをベースに生み出されたので、AndroidとiOSでしか有効でないものと思われがちですが、実際にはプラットフォームを限定しない抽象化を行っているため、react-native-windowsreact-native-macosといった、他のプラットフォームの抽象化にも成功しています。

React Nativeは「あらゆるGUIアプリケーションプラットフォームを抽象化するフレームワークである」と言えるのではないかとすら、筆者は感じています。

React Native for Webがブラウザに持ち込んだもの

Webブラウザ上でGUIアプリケーションを構築しようとした場合にも、React Nativeの「GUIアプリケーションを作るなら大抵こういうのが必要でしょ」というコンポーネントのラインナップは、やはり有効です。

React Native for Webは、ネイティブアプリをブラウザ上で再現しようとしたものではありません。React Nativeが提唱したGUIの抽象化を、Webアプリケーションの世界でも使えるようにした、ブラウザ向けのReactコンポーネント&便利モジュール集ライブラリです。

React Native本家のテクノロジスタックとは異なり、次の図のような構成になっています。

f:id:Nkzn:20180529203426p:plain

たまたまReact Nativeと似たようなラインナップのコンポーネントが、たまたま似たような名前のpropsを持っていて、たまたまReact Nativeと似たようなスタイルを持っている、ただそれだけです。スタイルやpropsに関する思想をReact Nativeに寄せてあるだけで、ライブラリとしてはmaterial-uiOnsen UIに近いとすらいえるでしょう。

コンポーネントが便利

というわけで、ただのブラウザ向けReactコンポーネントとしてみた場合に、どんなコンポーネントがあるかというと、

  • ぐるぐるを出してくれるActivityIndicator
  • 挟めばスクロールさせてくれるScrollView
  • 進捗を表示するProgressBar
  • 引っ張って更新のRefreshControl

こういうのが普通に使えるわけです。便利ですね。

スタイル周りも良い感じ

GUIアプリケーション、特にモバイルでの動作を意識したスタイルが最初から効いています。

例えばScrollViewには次のような特性があります。

  • 細かい設定をしなくてもScrollViewの中には慣性が効く
  • 細かい設定をしなくてもScrollViewの中身がオーバースクロールする

例えばこういうの↓を書いただけで、画像が縦にズラッと並んで、慣性スクロールも聴いて、一番下まで行ったらちょっとオーバースクロールもさせてくれるわけです。

<View>
  <ScrollView style={{flex:1}}>
    <Image />
    <Image />
    <Image />
    ...
  </ScrollView>
  <Text>画面下部に固定のテキスト</Text>
</View>

このへんはMobile Safariに苦しめられたことがあったので、地味に嬉しいです。

また、React NativeではレイアウトにFlexboxを採用しているのを踏襲して、次のような特性も持っています。

  • 常に display: flex が効いてる
  • flexDirection のデフォルト値が column (縦並び)

毎回 display: flex を書かなくていいのは完全に楽ですし、モバイル向けのアプリではアイテムを上から下に並べることが多いことから、flexDirectionを指定する機会が減るのも助かります。

TouchableOpacityでタップ表現もラクラク

TouchableOpacityは「タップイベントに応じて囲んだ内側のViewの透明度を変えるフィードバックを表現する」ためのコンポーネントです。

<TouchableOpacity onPress={() => { /* タッチイベント */}}>
  <View /> // 自作のボタンっぽいもの
</TouchableOpacity>

上記のようなコンポーネントを作った場合、内側のViewには一切タッチイベントに関する設定を行わなくても、簡単なフィードバックを実装することができます。

f:id:Nkzn:20180529200955g:plain

他にもいろいろあるけど

GUIアプリケーションを作る際に便利なあれこれが詰まっています。

React Native本家とコードの共通化、みたいな文脈もないわけではないですが、それよりも、単純にWebアプリ開発を便利にしてくれるツールだと思ったほうが気楽に試せると思います。

触ってみたくなった方向けに、create-react-app上にReact Native for Web環境を置いたボイラープレートを用意しておいたので、触ってみてください。

github.com

プロダクション事例が強すぎる

実は、PWAの事例として有名なTwitter Liteは、React Native for Webの事例でもあります。

Twitter LiteはReact Nativeによるネイティブアプリ版が存在するわけでもなく、純然たるWebアプリです。

こういった活用ができる程度には、React Native for WebはWebアプリ開発の文脈で有用なものであると筆者は考えます。

作者のnecolasも語ってた

https://twitter.com/necolas/status/983769332411805697

↑から始まる一連のツイートで、React Nativeそのものやfor Webの可能性について語っています。アツいです。

まとめ

React Native for Webは、React Nativeによって抽象化された「モバイルアプリ開発の当たり前」をブラウザの世界に持ち込んでくれる存在です。

単純にWebアプリ開発の負担を軽減してくれるところもありますし、ネイティブアプリ開発の出身者が初めてWebアプリ開発に携わったときに経験しやすい「えっ、こんなことも自分で工夫しないといけないの」を、いくらか軽減してくれる効果も期待できます。

ScrollViewなどを単独で使うこともできるので、皆さんのWebアプリの一部に取り込んでみてはいかがでしょうか。

余談:React系のアプリケーションフレームワーク

Reactベースでありながらまったく別のコードベースで開発が進められているフレームワークたちを挙げてみます。

  • React Native
    • Android, iOS向けのGUIアプリケーションフレームワーク
    • ネイティブ実装部分を差し替えただけのサードパーティ実装もある
      • react-native-windows(Windows)
      • react-native-macos(macOS)
      • react-native-dom(ブラウザ)
    • この辺の話は先日の記事が詳しい
  • React Native for Web + React DOM
    • ブラウザ向けのGUIアプリケーションフレームワーク
    • React Nativeのコンポーネントを模倣している
  • React 360
    • VRアプリのためのGUIアプリケーションフレームワーク
    • React Nativeのコンポーネントを模倣している
  • Ink
    • ターミナルのためのCLIアプリケーションフレームワーク
    • 独自の生態系を構築している

はい、Inkをオチに使いたかっただけです。

<Color green>
  {this.state.i} tests passed
</Color>

f:id:Nkzn:20180529205525g:plain

完全に独自の生態系ですよ・・・この発想はなかった・・・