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,
React NativeでiOSのランディングスクリーンに画像を設定する方法
という記事を書いた。
だいたい図にした。constrainsの設定の時だけ、対象のオブジェクトからviewへcontrol + click してドラッグというのがわかりにくいかも。