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 してドラッグというのがわかりにくいかも。
Presigned post to aws s3 from React Native
It took a longtime to figure out how to upload images to aws s3 using presigned post from React Native.
The key part is to use FormData to construct a payload and post it with POST
http method. PUT
ing FormData payload with pre-signed URL didn’t work for me at least.
Server Side
I use Ruby on Rails for server side here. Read Direct to S3 Image Uploads in Rails | Heroku Dev Center to fully understand the code below.
FYI: You don’t need to setup CORS settings in the article for native apps.
The security model for XMLHttpRequest is different than on web as there is no concept of CORS in native apps. - https://facebook.github.io/react-native/docs/network.html
Here is the code:
# In your controller def presigned_url options = { key: "uploads/photos/#{SecureRandom.uuid}/${filename}", success_action_status: '201', acl: 'public-read' } presigned_post = S3_BUCKET.presigned_post(options) # FIXME: http://stackoverflow.com/a/36941996/2930161 if presigned_post render plain: { presignedPost: { fields: presigned_post.fields, url: presigned_post.url } }.to_json, status: 200, content_type: 'application/json' else render plain: { error: 'No presigned urls.' }.to_json, status: 422, content_type: 'application/json' end end
React Native
// In your component. async _uploadToS3() { try { // implement your method to fetch a presigned post object. const presignedPost = await this._fetchPreSignedPost() let formData = new FormData(); Object.keys(presignedPost.fields).forEach((key) => { formData.append(key, presignedPost.fields[key]); }); formData.append('file', { // Provide an url of a target image. uri: this.image.uri, type: 'image/jpeg', name: 'image.jpg', }) const presignedUrl = presignedPost.url fetch(presignedUrl, { method: 'POST', body: formData, headers: { 'Content-Type': 'multipart/form-data'} }) } catch (error) { console.log(error) } }
This Answer on StackOverflow inspired me for the code, thanks:
Other Links
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Bucket.html#presigned_post-instance_method
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/PresignedPost.html
Upload an Object Using a Pre-Signed URL (AWS SDK for Ruby) - Amazon Simple Storage Service
react-native/XHRExampleFormData.js at master · facebook/react-native · GitHub