reactjs
react-native

真に Universal な ReactComponent を書く

ややお気持ち多め。

前置き

最近の個人的な考えとして、React 書く人は ReactNative 側にスキルを寄せたほうが良いのではないか、と思っている。

ReactNative の需要の高まりは凄い。最初はプロトタイピング採用だったのが、徐々にプロダクションに出始めている。今年末には新規プロジェクトの10~20%は ReactNative になるんじゃないか?という感すらある。

僕はデスクトップのブラウザは好きだけども、残念ながら、世の中の趨勢はモバイル側にある。その上でフロントエンドにロックインすることをリスクに感じている。PWAのアプリケーションも来そうではあるが、直近の需要を賄うためにやはりReactNativeに習熟しておきたい。

大事なのは、「考え方として」 ReactNative に軸足を移したほうが色々といいということだ。 Web は基本的に動きが少ない。見栄えをよくしたり、アニメーションを挟み込もうとする動機があまりない。その上で、モバイルの主戦場はこれらのインタラクションだ。そちら側で戦ったほうがエンジニアとして成長があるのではないか。

(あと、ReactだとかAngularだとか、Webで不必要な複雑性を持ち込みやがって、みたいな意見を、アプリを作ってるんですよ、という体で言い訳しやすい)

普通のWebを作る際も、ReactNative側にスキルを寄せた上で、 react-native-web 上で生活する、という選択肢をとりたい。そして、その際に必要なのは Universal な Component 定義であると思う。

styled-components/primitives による Universal な Component 定義

https://github.com/lelandrichardson/react-primitives というライブラリがある。これは Web と RN を抽象化したUI層だ。

styled-components/primitives は styled-components で react-primitives を通して使う。これらを react-native または react-native-web を通して使う。 (react-native-web を使った作例として、twitter.com のモバイル版がある https://mobile.twitter.com/home)

という感じでビルドできるプロジェクトを作った https://github.com/mizchi/rn-universal-components-boilerplate/tree/universal

こんな感じのコードが動く。

/* @flow */
import React from 'react'
import styled from 'styled-components/primitives'
import { Grid, Col } from 'react-native-easy-grid'

const Text = styled.Text`
  font-size: 32;
  color: palevioletred;
`

export default () => (
  <Grid>
    <Col>
      <Text>A</Text>
    </Col>
    <Col>
      <Text>B</Text>
    </Col>
    <Col>
      <Text>C</Text>
    </Col>
  </Grid>
)

(同じものが動いてるという検証であって、デザイン的にはしょぼいが…)

勿論実機でも動く。

react-native-easy-grid は react-native 用の グリッドライブラリだが、react-native-web でも動いている。

つまりは ReactNative の flex と styled-components の機能に限定したサブセットで書くことで、どの環境でも動くReactComponentが書ける。

実用的か

僕はそもそも今のCSSが嫌いなので、UIに密に結合した CSS は歓迎している。現代では、CSSとHTMLが暗黙のルールで密結合していることを、「装飾とセマンティクスが分離されている」と言っているとしか思えない。
静的なものだったらそれでいいと思うが、動的なコンテンツで潜在的に発現しうるセレクタを考慮しながら装飾をするのは非常に困難で、バグの温床でしかない、と思っている。

その上で、コンポーネント思考の設計を前提に、装飾の定義はコンポーネント内に閉じるはずだとして、styled-components が気に入っている。

RNを通すことで、実質的に flex 縛りなのもいい。下手に float レイアウトなんか目にするよりは健全である。ただし yoga レイアウトエンジンの表現に縛られるので grid layout は使えず、その点は退化している。

問題は、やはり既存の考え方から乖離が大きいことか。しかしReactNativeなんて新しい環境なんだから、とりあえず flex 縛りで、というのはそこまで大きなジャンプでもないような気もする。

やはり「可能ではあるが、縛りプレイ」みたいな結論が妥当であると思う。