Relay Modernへの移行検討をした
結論: もう少しドキュメントとサンプルが増えてからにしよう(rcが外れる頃かな?)
追記: 2017/08/21: 移行しました: Relay Modernに移行した - taiki-t's diary
背景
現在アプリを作っていて、フロント側の構成はReact Native + Relay + Reduxという感じだ。
(Relay Modern以前のバージョンはModernの登場によりRelay Classicと呼ばれるようになったのでこの記事でも以後Relay Classicと呼ぶ。)
ネットワークを介するデータについてRelay Classicは素晴らしく機能的だったが、ネットワークを介さないデータの管理には向いていない。というかRelay Classic標準ではできない。
そこで出てくる問題は、コンポーネントを跨いだアプリケーショングローバルのステート管理だ。(コンポーネント単位のローカルステートであればそのままReactのstate
, setState
を使って管理すれば良い)
つまりログインステータスなどをアプリケーション全体で一貫して管理するにはそこの層を導入する必要がある。
ReduxもしくはFluxがそこで登場するわけだが、自分の場合Reduxを選んだ。FacebookはFluxを使ってる/たとの話だ*1。
しかしやはりそのためにReduxなりFluxを導入するのは欲する結果と得る複雑性の観点から合理的とは言い難く(個人の感想)、issueなどでもローカルステートの管理をしたいとの要望などは上がっていた。
Relay Modernについて
Relay Modernでの改善については New in Relay Modern - Relay Docs に詳しいので再掲するようなことはしないが、今回Client Schema Extensionsなるものが入る。これはまさに上述の問題を解決するものだ。公式の説明にもそのように記述されている。
This should be able to replace some use cases that previously required a Flux/Redux store on the side.
– https://facebook.github.io/relay/docs/new-in-relay-modern.html#client-schema-extensions より一部抜粋
そのほかに導入された改善として目につくのは、
の2つだ。前者はRelay Classicに慣れ親しんだものにとっては移行コストであって、新規の人への恩恵が大きい。学習コストが下がってるはずだ。後者については、自分のアプリでもそう遠くないうちに導入したい機能だと思っている。
Relay Modernへの移行について
※ ほとんど個人的な話
まぁ自分の場合いまのアプリケーションで差し迫って必要なのはローカルステート問題を解決する機能なので、そこがアップデートへのモチベーションとなる。 ところが、そのClient Schema Extensionsについて具体的な実装に触れたドキュメントは2017/04/23現在、存在しない。 似たようなドキュメント難民の声がIssueに上がっていた。
提示されたリンクからいくらかざっと辿ってみたけれど、@export
というディレクティブを使うんだ、metadata
propsに入るのかな?ということぐらいしかわからなかった。
それでも試してみようかと思ったけど、そもそもIssueに答えたFB中の人が
but getting this to work outside the FB environment hasn’t yet happened.
– https://github.com/facebook/relay/issues/1656#issuecomment-296249276
と言っているので冒険にはまだ早いなと思いとどまった。もう少し合理的な努力ができそうになってからトライしよう。 そういう訳でまだアップデートしない。
*1:
2015/02/20 もう2年前の情報。2017年現在はどうなってるか知らない:
At Facebook, we have apps built entirely using Flux, entirely using Relay, or with both. One pattern we see emerging is letting Relay manage the bulk of the data flow for an application, but using Flux stores on the side to handle a subset of application state.
Grammarly cm の曲
Youtubeで流れていいなと思った
Soul City の Here I come というやつらしい
↓ みたCM
調べてみるとMarmosetという音楽出版社で配信している。映像に合わせるBGM向けのライセンス提供が主な業態らしい。個人で試聴するぶんには無料でダウンロードできた。自分の映像にマッチするかちゃんと検証するためには全部聞けないとね、ということらしい。
ということで、結婚式の映像につけるとかpodcastで流すとか、作品や配信に使う人はライセンス契約してね。
曲のページ:
Marmoset // Here I Come by Soul City
ライセンス:
ライセンスもクラウドファンディング向けとか、スモールビジネス向けだとか、色々あって面白い。
Marmoset:
広告:
- 作者: Raymond Murphy
- 出版社/メーカー: Cambridge University Press
- 発売日: 2015/07/30
- メディア: ペーパーバック
- この商品を含むブログを見る
React Navigationにコントリビュートした
React Navigation, APIはいい感じなんだけど現状beta版ということもあり、プロダクションで使っていこうと思うとなかなか機能が足りない。 それで2017/4/7現在では、v1リリースに向けて最低限必要な機能を実装していこうという状態にある。(と信じている)
その不足してる機能の一つが、「ネストされたルーターからナビゲーションをリセットできる」ことだ。現状はできない。
で、先日そのPRが出て無事マージされたんだけど、どうやら別の機能(setParams
)がうまく動かなくなっていた。
ので、コードを変更しテストを書きPRを出したところ、無事マージしてもらえた。
よかった(感想)。
React Navigation は React Native本体のコアコントリビューターたちも絡んでいる。出したPRもFacebookでRNを作ってる中の人に見てもらえた。 そういう意味ではReact Native本体にPRを出していく肩慣らしとしてReact Navigationはちょうど良いプロジェクトかもしれない。 React NativeにPRを出すにはContributor License Agreement (CLA) にサインする必要があったりと多少敷居が高いが、 こちらは特にCLAにサインする必要もない。普通にPR送れば良い。のでみんなでコントリビュートしてv1リリースしよう。(ポジショントーク)
あとがき
React Native本体はこのissueのコメントが役に立ってるぽいぐらいのことしかまだしてないので、今後もう少し折をみて寄与していけたらと思う。
おーい磯野〜 callback使ってる関数をPromiseでラップしてasync/awaitで書こうぜ〜
例1
const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } const something = async () => { await sleep(100) doSomething() }
例2
Geolocation.getCurrentPosition() - Web API インターフェイス | MDN から
// 元メソッドの構文は // navigator.geolocation.getCurrentPosition(success, error, options) // クラスの中 getCurrentPosition(options) { return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject, options) }) } async something() { try { let position = await this.getCurrentPosition() this.doSomething(position) } catch(error) { console.log(error) } }
例3
値を二つ返す系 例は React Nativeから Image コンポーネントのgetSizeメソッド
// 元メソッドの構文: getSize(uri: string, success: function, failure?: function) // クラスの中 _getSize(uri) { return new Promise((resolve, reject) => { Image.getSize(uri, (width, height) => { resolve({width, height}) }, reject) }) } async something(imageUri) { try { let { width, height } = await this._getSize(imageUri) this.doSomething(width, height) } catch(error) { console.log(error) } }
Reactエレメント、コンポーネント、そしてインスタンス
React Components, Elements, and Instances - React Blog
を読んだメモ
エレメント(要素)
- エレメントは、コンポーネントインスタンスまたはDOMノードを記述する、普通のオブジェクト
- エレメントは、実際のインスタンスではない
- エレメントは、何を画面上に見たいかReactに伝えるための手段(記述)
- エレメントは、コンポーネントのタイプを表す
type
フィールドと、そのプロパティを表すprops
フィールドから成る*1。- 子要素があれば、それも含むことになる
- エレメントは、記述のためのイミュータブルなオブジェクトに過ぎない
DOMエレメントとコンポーネントエレメント
DOMエレメント
- エレメントの
type
が文字列であるとき、エレメントはそのタグ名をもつDOMノードを表す。エレメントのprops
フィールドは、そのDOMノードの属性に対応する - 子要素も親要素も単なる記述に過ぎず、記述した時点では画面上のものへの参照を一切持たない
- 画面上に見たいDOMを記述するエレメント
コンポーネントエレメント
- エレメントの
type
は文字列以外にも、Reactコンポーネントに一致するクラスか関数もとれる - コンポーネントを記述するエレメントもまたエレメント
- これにより継承(is-a)とコンポジション(has-a)関連を表現できる
- 画面上に見たいコンポーネントを記述するエレメント
DOMエレメントとコンポーネントエレメントの関係
- Reactはコンポーネントエレメント(
type
が関数もしくはクラスであるエレメント)を見つけると、そのコンポーネントが、与えられたprops
と共にどんなエレメントを吐き出すのかをたずねる- ( Reactコンポーネントは、propsを入力にとり、エレメントツリーを出力する )
- Reactはこのプロセスを、最終のDOMタグになるまで繰り返す
コンポーネント
- コンポーネントは、エメレントツリーをカプセル化するもの
- Reactコンポーネントは、propsを入力にとり、エレメントツリーを出力する
- Reactコンポーネントが返すエレメントツリーはDOMエレメントとコンポーネントエレメントの両方を含みうる
- コンポーネントはクラスもしくは関数
- クラスはもう少し機能が豊富だけど、Reactからすればどちらも基本的にはコンポーネント
- どちらもpropsを入力にとり、エレメントツリーを出力する
画面に見たいものを記述すれば、そのインスタンスの管理(作成、更新、削除)はReactがよしなにやってくれる。
インスタンス
- Reactにおいては、他のオブジェクト指向UIフレームワークに比べてインタンスはさほど重要でない
- クラスとして宣言されたコンポーネントのみがインタンスを持つ。関数のコンポーネントはインスタンスを一切持たない
- プログラマが直接インスタンスを作ることはない。 Reactが作ってくれる
- インスタンスは、コンポーネントクラス内で
this
として参照されるもの
*1:説明の簡単のために省かれたが、実際はもう一つフィールドがある
React Nativeでのナビゲーションに便利なReact Navigation
2018-5-10追記: 先日v2も出ました。今目にしているブログ記事はだいぶ古いと思うので注意です。React Navigation (v2) · Routing and navigation for your React Native apps
2017/9/15追記: React Navigationは開発サイクルがしばらく停滞していたけれど、最近仕切り直しがあった。うまく行くといいな。https://reactnavigation.org/blog/2017/9/Renewed-v1
2017/3/17追記: beta-7時点で、ネストされたナビゲーター内からナビゲーター全体のstackをリセットできないという問題がある。ので、認証してトップに戻るとか、アップロード完了したらトップに戻るとかまともにできないと思うので辛そう。Specify reset key to define what state should be reset · Issue #691 · react-navigation/react-navigation · GitHub
2017/3/15追記: 記事中で「ナビゲーションライブラリは収束しつつある模様」という旨のことを書いたけれども、昨日Airbnbからナビゲーションライブラリが発表されたりと、依然動きはある。ExNavigationとNavigationExperimentalはReact Navigationに後続したというのが観測範囲。*1 *2
React Nativeでのナビゲーションは、標準のコンポーネント(Navigation
)だと辛いものがあった。
そこでいくつか他の実装が出てきてたのだけど(ExNavigationとか)、最近はReact Navigation (v2) · Routing and navigation for your React Native appsに収束しつつある模様。
手元のプロジェクトでも使っているけど、見通しが良いコードを書けたのでかなり満足。
Navigation
での辛さを解決するための、Navigation Experimental
というその名の通り実験的なコンポーネントも一応React Native内で提供されていたけど、0.43.0からはDeprecatedになる。公式でも React Navigation 推しになるからだ。
React Nativeであれば、index.ios.js
で以下のようにコンポーネントを読み込んで、ルーティングを書いてやればよい。
import { StackNavigator, } from 'react-navigation'; const BasicApp = StackNavigator({ Main: {screen: MainScreen}, Profile: {screen: ProfileScreen}, });
他のスクリーン(コンポーネント)内から目的のスクリーンに遷移する際は以下のようにnavigate('Profile', { name: 'Jane' })
と、遷移先のKeyと、必要に応じてプロパティをメソッドに渡す。
class MainScreen extends React.Component { static navigationOptions = { title: 'Welcome', }; render() { const { navigate } = this.props.navigation; return ( <Button title="Go to Jane's profile" onPress={() => navigate('Profile', { name: 'Jane' }) } /> ); } }
なお上記の例はReact Navigation (v2) · Routing and navigation for your React Native appsからそのまま拝借したもの。
懸念があるとすれば、2017/3/9現在のバージョンがv1.0.0-beta.6
であることだ。個人的にもそこにためらいがあったものの、試しに導入して見たところ手元のユースケースの範囲では特段困ることはなかったので導入してしまった(計9スクリーン、TabとStackのネスト。そこまで大きくない)。得られる恩恵が大きすぎた。
また、React Nativeコミュニティが関わっているプロジェクトに対する信頼もある。レポジトリやコミュニティを眺める限り、Breaking changesがあればそれ相応のマイグレーションのための対応がされるはずだと信じている。
そういえば、先日のReact Native Team AMA Liveでも、これからReact Native始めるなら現時点ではReact Navigationを見るといいって言及されてたっけな。
6:14秒あたりから。そのちょっと前には、Reactでwebアプリ書き始めるならReact Router使うといいよ、って言ってる。
React Navigation (v2) · Routing and navigation for your React Native apps
関連
書いた: メモ: React Navigation を使い始める時に確認すると良さそうなこと (v1.0.0-beta.10時点) - taiki-t's diary
*1:https://reactnavigation.org/blog/2017/1/Introducing-React-Navigation には次のように記載されている。
It replaces and improves upon several navigation libraries in the ecosystem, including Ex-Navigation and React Native's Navigator and NavigationExperimental components.
GitHub - expo/ex-navigation: Route-centric navigation for React Native には
The successor to ExNavigation, "react-navigation", is now in public beta.
NavigationExperimentalについては冒頭のdeprecation commitより
The NavigationExperimental views live on in the React-Navigation project,