メインコンテンツへスキップ

React Nativeマンスリー #1

·6分で読めます
Tomislav Tenodi
Shoutem プロダクトマネージャー

Shoutemでは、React Nativeのごく初期の段階から関わる機会に恵まれました。私たちは、初日からこの素晴らしいコミュニティの一員になりたいと決意しました。すぐに、コミュニティの成長と改善のペースに追いつくのはほぼ不可能だと気づきました。そのため、主要なReact Nativeコントリビューターが各自の取り組みと計画を簡潔に発表できる月例会議を組織することにしました。

月例会議

月例会議の最初のセッションは2017年6月14日に開催されました。React Native Monthlyのミッションはシンプルかつ明確です。React Nativeコミュニティを改善すること。チームの取り組みを発表することで、オフラインで行われるチーム間の連携が容易になります。

チーム

第1回ミーティングには、8つのチームが参加しました。

今後のセッションでは、より多くのコアコントリビューターが参加してくれることを期待しています!

ノート

各チームの計画は、より広い層の関心事となる可能性があるため、ここReact Nativeブログで共有します。以下がその内容です。

Airbnb

  • ViewAccessibilityInfoネイティブモジュールにA11y (アクセシビリティ) APIを追加する予定です。
  • Androidのネイティブモジュールに、実行スレッドを指定できるAPIを追加することを検討します。
  • 初期化パフォーマンスを改善する可能性について調査を進めています。
  • 「unbundle」の上に、さらに洗練されたバンドル戦略をいくつか検討しています。

Callstack

  • E2EテストにDetoxを使用することで、リリースプロセスの改善を検討しています。プルリクエストは間もなく提出される予定です。
  • 取り組んできたBlobのプルリクエストがマージされ、後続のプルリクエストも準備中です。
  • Metro Bundlerと比較してHaulがどのように機能するかを見るため、社内プロジェクト全体でその採用を増やしています。webpackチームと連携して、より優れたマルチスレッドパフォーマンスに取り組んでいます。
  • 社内で、オープンソースプロジェクトを管理するためのより良いインフラを実装しました。今後数週間で、より多くのものを公開する予定です。
  • React Native Europeカンファレンスが近づいていますが、まだ特筆すべきことはありません。皆さん、ぜひご参加ください!
  • 代替案(特にネイティブナビゲーション)を調査するため、react-navigationから一時的に離れています。

Expo

  • Snackでnpmモジュールをインストールできるようにする作業を進めています。これはライブラリがドキュメントにサンプルを追加する際に役立つでしょう。
  • Software MansionKrzysztofや他の人々と協力して、AndroidでのJSCアップデートとジェスチャーハンドリングライブラリに取り組んでいます。
  • Adam Miskiewiczは、react-navigationに焦点を移しています。
  • Create React Native Appはドキュメントの入門ガイドにあります。Expoは、ライブラリの作者に、そのライブラリがCRNAで動作するかどうか、動作する場合、どのようにセットアップするかを明確に説明するよう促したいと考えています。

Facebook

  • React Nativeのパッケー​​ジャーは現在、独立したリポジトリであるMetro Bundlerです。ロンドンにいるMetro Bundlerチームは、コミュニティのニーズに対応し、React Native以外の追加のユースケースのためのモジュール性を改善し、問題やPRへの対応を迅速化することに意欲を燃やしています。
  • 今後数ヶ月で、React NativeチームはプリミティブコンポーネントのAPIを洗練させる作業に取り組みます。レイアウトの癖、アクセシビリティ、Flowの型付けに関する改善が期待されます。
  • React Nativeチームは今年、WindowsやmacOSといったサードパーティプラットフォームを完全にサポートするためのリファクタリングを行い、コアのモジュール性を向上させる計画です。

GeekyAnts

  • チームは、.jsファイルを直接操作するUI/UXデザインアプリ(コードネーム:Builder)を開発中です。現在はReact Nativeのみをサポートしており、Adobe XDやSketchに似ています。
  • 既存のReact Nativeアプリをエディタで読み込み、(デザイナーとして視覚的に)変更を加え、その変更を直接JSファイルに保存できるようにするため、チームは懸命に取り組んでいます。
  • デザイナーと開発者の間の溝を埋め、同じリポジトリで作業できるようにすることを目指しています。
  • また、NativeBaseは最近、GitHubスターが5,000に達しました。

Microsoft

  • CodePushは現在、Mobile Centerに統合されています。これは、配布、分析、およびその他のサービスとのより統合されたエクスペリエンスを提供する最初のステップです。発表はこちらをご覧ください。
  • VS Codeにはデバッグに関するバグがあり、現在その修正に取り組んでおり、新しいビルドが提供される予定です。
  • 統合テストのためにDetoxを調査しており、クラッシュレポートと共に変数を取得するためにJSC Contextに注目しています。

Shoutem

  • React Nativeコミュニティのツールを使ってShoutemアプリでの作業をより簡単にします。Shoutemで作成されたアプリを実行するために、すべてのReact Nativeコマンドを使用できるようになります。
  • React Nativeのプロファイリングツールを調査しています。セットアップに多くの問題があったため、その過程で得られた知見をいくつか書き出す予定です。
  • Shoutemは、React Nativeを既存のネイティブアプリと統合しやすくする作業に取り組んでいます。コミュニティからのフィードバックを得るため、社内で開発したコンセプトをドキュメント化する予定です。

Wix

  • Wixアプリの重要な部分を「手動QAなし」にするために、Detoxを社内で採用するよう取り組んでいます。その結果、Detoxは数十人の開発者によって本番環境で extensively 使用され、急速に成熟しています。
  • ビルド時に任意のファイル拡張子をオーバーライドできるようにMetro Bundlerのサポートを追加する作業を行っています。「ios」や「android」だけでなく、「e2e」や「detox」のようなカスタム拡張子もサポートします。E2Eモックにこれを使用する計画です。react-native-repackagerというライブラリはすでに公開されており、現在PRに取り組んでいます。
  • パフォーマンステストの自動化を調査しています。これはDetoxInstrumentsという新しいリポジトリです。オープンソースで開発されているので、ぜひご覧ください。
  • KPNのコントリビューターと協力して、Android版Detoxと実機でのサポートに取り組んでいます。
  • シミュレーター/デバイスを自動化する必要がある他のツールを構築できるように、「プラットフォームとしてのDetox」を検討しています。例としては、React Native用のStorybookや、Ramの結合テストのアイデアがあります。

次のセッション

会議は4週間ごとに開催されます。次回のセッションは2017年7月12日に予定されています。この会議を開始したばかりですので、これらのメモがReact Nativeコミュニティにどのように役立つかを知りたいです。次回のセッションで取り上げるべき内容や、会議の成果をどのように改善すべきかについて何か提案がありましたら、Twitterで私にメッセージを送ってください。

React Nativeでのより良いリストビュー

·6分で読めます
Spencer Ahrens
Facebook ソフトウェアエンジニア

コミュニティグループでの予告発表後、多くの方がすでに新しいリストコンポーネントを試されていますが、本日、正式にそれらを発表します!もはやListViewDataSource、古い行、無視されたバグ、過剰なメモリ消費はもうありません。最新のReact Native 2017年3月リリース候補(0.43-rc.1)では、新しいコンポーネントスイートから、使用ケースに最も適したものを選択できます。これらは優れたパフォーマンスと機能セットをすぐに提供します。

<FlatList>

これはシンプルでパフォーマンスの高いリストのための主力コンポーネントです。データの配列とrenderItem関数を指定すれば、すぐに利用できます。

<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>

<SectionList>

データを論理的なセクションに分割してレンダリングしたい場合(例えば、アルファベット順のアドレス帳でのセクションヘッダーなど)、そして異種データとレンダリング(例えば、いくつかのボタン、次にコンポーザー、次に写真グリッド、次にフレンドグリッド、最後にストーリーのリストを含むプロファイルビューなど)を扱う場合、これが最適な方法です。

<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>

<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>

<VirtualizedList>

より柔軟なAPIを備えた舞台裏の実装です。データが単純な配列ではない場合(イミュータブルなリストなど)に特に便利です。

機能

リストは多くの文脈で使用されるため、新しいコンポーネントには、ほとんどのユースケースをすぐに処理できる機能が満載されています。

  • スクロールによる読み込み(onEndReached)。
  • Pull to refresh(onRefresh / refreshing)。
  • 設定可能な視認性(VPV)コールバック(onViewableItemsChanged / viewabilityConfig)。
  • 水平モード(horizontal)。
  • インテリジェントなアイテムとセクションのセパレータ。
  • 複数カラムのサポート(numColumns)。
  • scrollToEndscrollToIndex、およびscrollToItem
  • より良いFlowタイピング。

いくつかの注意点

  • コンテンツがレンダーウィンドウの外にスクロールされると、アイテムのサブツリーの内部状態は保持されません。すべてのデータがアイテムデータまたはFlux、Redux、Relayなどの外部ストアにキャプチャされていることを確認してください。

  • これらのコンポーネントはPureComponentに基づいているため、propsがシャロー比較で等しいままであれば再レンダリングされません。renderItem関数が直接依存するすべてのものが、更新後も===ではないプロップとして渡されていることを確認してください。そうしないと、変更時にUIが更新されない可能性があります。これにはdataプロップと親コンポーネントの状態が含まれます。例:

    <FlatList
    data={this.state.data}
    renderItem={({item}) => (
    <MyItem
    item={item}
    onPress={() =>
    this.setState(oldState => ({
    selected: {
    // New instance breaks `===`
    ...oldState.selected, // copy old data
    [item.key]: !oldState.selected[item.key], // toggle
    },
    }))
    }
    selected={
    !!this.state.selected[item.key] // renderItem depends on state
    }
    />
    )}
    selected={
    // Can be any prop that doesn't collide with existing props
    this.state.selected // A change to selected should re-render FlatList
    }
    />
  • メモリを制限し、スムーズなスクロールを可能にするために、コンテンツはオフスクリーンで非同期にレンダリングされます。これは、フィルレートよりも速くスクロールすると、一時的に空白のコンテンツが表示される可能性があることを意味します。これは各アプリケーションのニーズに合わせて調整できるトレードオフであり、私たちは舞台裏で改善に取り組んでいます。

  • デフォルトでは、これらの新しいリストは各アイテムのkeyプロップを探し、それをReactのキーとして使用します。代わりに、カスタムのkeyExtractorプロップを提供することもできます。

パフォーマンス

APIを簡素化するだけでなく、新しいリストコンポーネントは大幅なパフォーマンス向上も実現しています。その主なものは、どんな行数でもメモリ使用量がほぼ一定になることです。これは、レンダリングウィンドウの外にある要素をコンポーネント階層から完全にアンマウントし、ReactコンポーネントのJSメモリと、シャドーツリーおよびUIビューのネイティブメモリを再利用することで、要素を「仮想化」することによって行われます。これには内部コンポーネントの状態が保持されないという注意点があるため、**重要な状態はコンポーネント自体ではなく、RelayやRedux、Fluxストアなど、コンポーネントの外部で追跡するようにしてください。**

レンダリングウィンドウを制限することで、ビューの走査など、Reactやネイティブプラットフォームが行う必要がある作業量も削減されます。たとえ100万個の要素の最後のものをレンダリングする場合でも、これらの新しいリストを使用すると、レンダリングのためにそれらすべての要素を繰り返し処理する必要はありません。scrollToIndexを使用すれば、過度なレンダリングなしで途中にジャンプすることもできます。

スケジューリングにもいくつかの改善を加え、アプリケーションの応答性を向上させるはずです。レンダリングウィンドウの端にあるアイテムは、アクティブなジェスチャーやアニメーション、その他のインタラクションが完了した後、低頻度かつ低優先度でレンダリングされます。

高度な使用法

ListViewとは異なり、レンダリングウィンドウ内のすべてのアイテムは、プロップが変更されるたびに再レンダリングされます。ウィンドウ処理によりアイテム数が一定に抑えられるため、多くの場合これで問題ありませんが、アイテムが複雑な場合は、パフォーマンスのためにReactのベストプラクティスに従い、コンポーネント内でReact.PureComponentshouldComponentUpdateを適切に使用して、再帰的なサブツリーの再レンダリングを制限するようにしてください。

行をレンダリングせずに高さを計算できる場合、getItemLayoutプロップを提供することでユーザーエクスペリエンスを向上させることができます。これにより、例えばscrollToIndexで特定のアイテムにスクロールする際がはるかにスムーズになり、コンテンツの高さをレンダリングせずに決定できるため、スクロールインジケーターのUIも向上します。

イミュータブルなリストのような代替データ型がある場合は、<VirtualizedList>が最適です。これはgetItemプロップを受け取り、任意のインデックスのアイテムデータを返すことができ、より緩やかなFlowタイピングを持っています。

また、珍しい使用ケースがある場合は、調整できる多数のパラメーターがあります。例えば、windowSizeを使用してメモリ使用量とユーザーエクスペリエンスのトレードオフを行ったり、maxToRenderPerBatchでフィルレートと応答性を調整したり、onEndReachedThresholdでスクロール読み込みのタイミングを制御したりできます。

今後の作業

  • 既存のサーフェスの移行(最終的にはListViewの非推奨化)。
  • 必要性を見聞きするにつれて、より多くの機能を追加(ぜひお知らせください!)。
  • スティッキーなセクションヘッダーのサポート。
  • さらなるパフォーマンスの最適化。
  • 状態を持つ関数型アイテムコンポーネントのサポート。

idx: 存在関数

·2分で読めます
Timothy Yung
Facebook エンジニアリングマネージャー

Facebookでは、GraphQLで取得したデータ構造内の深くネストされた値にアクセスする必要があることがよくあります。これらの深くネストされた値にアクセスする過程で、1つまたは複数の中間フィールドがnullになりうることがよくあります。これらの中間フィールドがnullになる理由は、プライバシーチェックの失敗から、単にnullが致命的ではないエラーを表す最も柔軟な方法であるという事実まで、さまざまです。

残念ながら、これらの深くネストされた値へのアクセスは、現在、面倒で冗長です。

props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends;

ECMAScriptの提案に、オプショナルチェイニング演算子を導入するものがあり、これによりアクセスがはるかに便利になります。しかし、その提案が最終決定されるまでは、私たちの生活の質を向上させ、既存の言語セマンティクスを維持し、Flowによる型安全性を促進するソリューションが必要です。

私たちは idx と呼ぶ存在**関数**を考案しました。

idx(props, _ => _.user.friends[0].friends);

このコードスニペットの呼び出しは、上記のコードスニペットのブール式と同様に動作しますが、繰り返しが大幅に少なくなっています。`idx` 関数は正確に2つの引数を取ります。

  • 任意の値。通常は、ネストされた値にアクセスしたいオブジェクトまたは配列。
  • 最初の引数を受け取り、その中のネストされた値にアクセスする関数。

理論的には、idx関数は、nullまたはundefinedのプロパティにアクセスした結果発生するエラーをtry-catchします。そのようなエラーがキャッチされた場合、nullまたはundefinedを返します。(そして、これがidx.jsでどのように実装されているかを見ることができます。)

実際には、ネストされたプロパティアクセスごとにtry-catchすることは遅く、特定の種類のTypeErrorを区別することは脆弱です。これらの欠点に対処するため、上記のidx呼び出しを以下の式に変換するBabelプラグインを作成しました。

props.user == null
? props.user
: props.user.friends == null
? props.user.friends
: props.user.friends[0] == null
? props.user.friends[0]
: props.user.friends[0].friends;

最後に、idx のカスタム Flow 型宣言を追加しました。これにより、2番目の引数内の走査が適切に型チェックされつつ、ヌル許容プロパティへのネストされたアクセスが許可されます。

関数、Babelプラグイン、およびFlow宣言は、現在GitHubで公開されています。これらは、idxおよびbabel-plugin-idx npmパッケージをインストールし、.babelrcファイルのプラグインリストに「idx」を追加することで使用できます。

Create React Native Appの紹介

·3分で読めます
Adam Perry
Expo ソフトウェアエンジニア

本日、Create React Native Appを発表します。これは、React Nativeプロジェクトをより簡単に始めるための新しいツールです。これはCreate React Appのデザインに強く影響を受けており、FacebookExpo(旧Exponent)の共同作業の成果です。

多くの開発者は、特にAndroidの場合、React Nativeの現在のネイティブビルド依存関係のインストールと設定に苦労しています。Create React Native Appを使用すると、XcodeやAndroid Studioを使用する必要がなく、LinuxまたはWindowsを使用してiOSデバイス向けに開発できます。これは、ネイティブコードをコンパイルすることなく、純粋なJavaScriptで書かれたCRNAプロジェクトをロードして実行するExpoアプリを使用して実現されます。

新しいプロジェクトを作成してみてください(yarnがインストールされている場合は、適切なyarnコマンドに置き換えてください)。

$ npm i -g create-react-native-app
$ create-react-native-app my-project
$ cd my-project
$ npm start

これにより、React Nativeのパッカーが起動し、QRコードが表示されます。Expoアプリで開いてJavaScriptをロードしてください。console.logへの呼び出しはターミナルに転送されます。標準のReact Native APIやExpo SDKを利用できます。

ネイティブコードについては?

多くのReact Nativeプロジェクトには、コンパイルする必要のあるJavaまたはObjective-C/Swiftの依存関係があります。Expoアプリにはカメラ、ビデオ、連絡先などのAPIが含まれており、Airbnbのreact-native-mapsFacebook認証などの一般的なライブラリもバンドルされています。しかし、Expoがバンドルしていないネイティブコードの依存関係が必要な場合は、おそらく独自のビルド構成が必要になります。Create React Appと同様に、「ejecting」はCRNAでサポートされています。

npm run ejectを実行すると、react-native initが生成するものと非常によく似たプロジェクトが得られます。その時点では、react-native initで開始した場合と同様に、XcodeやAndroid Studioが必要になり、react-native linkでライブラリを追加できるようになり、ネイティブコードのコンパイルプロセスを完全に制御できるようになります。

質問ですか?フィードバックですか?

Create React Native Appは一般利用に十分な安定性を備えており、その使用経験について皆様からのご意見を eagerly お待ちしております!私にはTwitterで連絡するか、GitHubリポジトリでissueを開いてください。プルリクエストも大歓迎です!

Animatedでネイティブドライバーを使用する

·6分で読めます
Janic Duplessis
App & Flow のソフトウェアエンジニア

この1年間、私たちはAnimatedライブラリを使用するアニメーションのパフォーマンス向上に取り組んできました。アニメーションは美しいユーザーエクスペリエンスを作成するために非常に重要ですが、正しく行うのは難しい場合があります。開発者が、一部のコードがラグを引き起こすことを心配することなく、パフォーマンスの高いアニメーションを簡単に作成できるようにしたいと考えています。

これは何ですか?

Animated APIは、非常に重要な制約、つまりシリアル化可能であることを念頭に置いて設計されました。これは、アニメーションが開始される前にアニメーションに関するすべてをネイティブに送信できることを意味し、ネイティブコードがフレームごとにブリッジを介することなくUIスレッドでアニメーションを実行できるようにします。アニメーションが開始されるとJSスレッドがブロックされる可能性があり、それでもアニメーションはスムーズに実行されるため、これは非常に便利です。実際、ユーザーコードはJSスレッドで実行され、ReactのレンダリングもJSを長時間ロックする可能性があるため、これは頻繁に発生します。

少し歴史を...

このプロジェクトは、ExpoがAndroid版li.stアプリを開発した約1年前に始まりました。Krzysztof MagieraがAndroid版の初期実装を請け負いました。結果的にうまく機能し、li.stはAnimatedを使ってネイティブ駆動のアニメーションを搭載した最初のアプリとなりました。数ヶ月後、Brandon WithrowがiOS版の初期実装を開発しました。その後、Ryan Gombaと私が、Animated.eventのサポートなどの不足している機能の追加や、本番アプリで使用する際に発見されたバグの修正に取り組みました。これは真にコミュニティの努力であり、関わってくださったすべての方々、そして開発の大部分を後援してくれたExpoに感謝したいと思います。これは現在、React NativeのTouchableコンポーネントや、新しくリリースされたReact Navigationライブラリのナビゲーションアニメーションで使用されています。

仕組み

まず、JSドライバーを使用してAnimatedでアニメーションが現在どのように機能するかを見てみましょう。Animatedを使用する場合、実行したいアニメーションを表すノードのグラフを宣言し、事前定義された曲線を使用してAnimated値を更新するためにドライバーを使用します。Animated.eventを使用して、Animated値をViewのイベントに接続して更新することもできます。

以下に、アニメーションの手順とそれがどこで発生するかを示します。

  • JS: アニメーションドライバーは、requestAnimationFrameを使用して毎フレーム実行され、アニメーションカーブに基づいて計算された新しい値を使用して、駆動する値を更新します。
  • JS: 中間値が計算され、Viewにアタッチされたプロップノードに渡されます。
  • JS: setNativePropsを使用してViewが更新されます。
  • JSからネイティブブリッジ。
  • ネイティブ: UIViewまたはandroid.Viewが更新されます。

ご覧の通り、ほとんどの作業はJSスレッドで行われます。JSスレッドがブロックされると、アニメーションはフレームをスキップします。また、ネイティブビューを更新するために、毎フレームJSからネイティブブリッジを通過する必要があります。

ネイティブドライバーが行うことは、これらのすべてのステップをネイティブに移動することです。Animatedはアニメーションノードのグラフを生成するため、アニメーションが開始されるときに一度だけシリアル化してネイティブに送信できるため、JSスレッドへのコールバックの必要がなくなります。ネイティブコードは、すべてのフレームでUIスレッドでビューを直接更新することができます。

アニメーション値と補間ノードをシリアライズする方法の例を次に示します(厳密な実装ではなく、単なる例です)。

ネイティブ値ノードを作成します。これがアニメーションされる値です。

NativeAnimatedModule.createNode({
id: 1,
type: 'value',
initialValue: 0,
});

ネイティブ補間ノードを作成します。これは、ネイティブドライバーに値を補間する方法を指示します。

NativeAnimatedModule.createNode({
id: 2,
type: 'interpolation',
inputRange: [0, 10],
outputRange: [10, 0],
extrapolate: 'clamp',
});

ネイティブプロップスノードを作成します。これは、ネイティブドライバーに、接続されているビューのどのプロップを対象とするかを指示します。

NativeAnimatedModule.createNode({
id: 3,
type: 'props',
properties: ['style.opacity'],
});

ノードを接続する

NativeAnimatedModule.connectNodes(1, 2);
NativeAnimatedModule.connectNodes(2, 3);

プロップノードをビューに接続する

NativeAnimatedModule.connectToView(3, ReactNative.findNodeHandle(viewRef));

これで、ネイティブのアニメーションモジュールは、JSに値を計算させることなく、ネイティブビューを直接更新するために必要なすべての情報を持っています。

残っているのは、どのようなタイプのアニメーションカーブが必要か、どのアニメーション値を更新するかを指定して、実際にアニメーションを開始することだけです。タイミングアニメーションは、ネイティブの実装を小さくするために、JSでアニメーションのすべてのフレームを事前に計算することで簡素化することもできます。

NativeAnimatedModule.startAnimation({
type: 'timing',
frames: [0, 0.1, 0.2, 0.4, 0.65, ...],
animatedValueId: 1,
});

そして、アニメーション実行時に何が起こるかの内訳を次に示します。

  • ネイティブ: ネイティブアニメーションドライバーは、CADisplayLinkまたはandroid.view.Choreographerを使用して毎フレーム実行され、アニメーションカーブに基づいて計算された新しい値を使用して、駆動する値を更新します。
  • ネイティブ: 中間値が計算され、ネイティブビューにアタッチされたプロップノードに渡されます。
  • ネイティブ: UIViewまたはandroid.Viewが更新されます。

ご覧のとおり、JSスレッドもブリッジも必要なくなり、アニメーションがより速くなります!🎉🎉

アプリでこれを使用するにはどうすればよいですか?

通常のアニメーションの場合、答えは簡単です。アニメーションを開始するときに、アニメーション設定にuseNativeDriver: trueを追加するだけです。

変換前

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
}).start();

変換後

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // <-- Add this
}).start();

アニメーション値は1つのドライバーとのみ互換性があるため、ある値のアニメーションを開始する際にネイティブドライバーを使用した場合、その値に対するすべてのアニメーションでもネイティブドライバーを使用するようにしてください。

これはAnimated.eventでも機能します。これは、スクロール位置に従う必要のあるアニメーションがある場合に非常に便利です。なぜなら、ネイティブドライバーがないと、React Nativeの非同期の性質により、常にジェスチャーより1フレーム遅れて実行されるからです。

変換前

<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }]
)}
>
{content}
</ScrollView>

変換後

<Animated.ScrollView // <-- Use the Animated ScrollView wrapper
scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }],
{ useNativeDriver: true } // <-- Add this
)}
>
{content}
</Animated.ScrollView>

注意点

Animatedでできることすべてが、現在Native Animatedでサポートされているわけではありません。主な制限は、非レイアウトプロパティのみをアニメーション化できることです。transformopacityのようなものは機能しますが、Flexboxや位置プロパティは機能しません。もう1つはAnimated.eventに関するもので、これは直接イベントでのみ機能し、バブリングイベントでは機能しません。これは、PanResponderでは機能しないが、ScrollView#onScrollのようなものでは機能することを意味します。

Native AnimatedはReact Nativeの一部としてかなり前から存在していましたが、実験的とみなされていたため、文書化されていませんでした。そのため、この機能を使用したい場合は、React Nativeの新しいバージョン(0.40以降)を使用していることを確認してください。

リソース

アニメーションに関する詳細については、Christopher Chedeauによるこの講演を視聴することをお勧めします。

アニメーションと、それらをネイティブにオフロードすることがユーザーエクスペリエンスをどのように向上させるかについて深く掘り下げたい場合は、Krzysztof Magieraによるこの講演もあります。

月次リリースサイクル: 12月と1月のRCをリリース

·3分で読めます
Eric Vicenti
Facebook エンジニア

React Nativeが導入されて間もなく、私たちはコミュニティが新機能を導入するのを助け、同時にプロダクション用途でバージョンを安定させるために、2週間ごとにリリースを開始しました。Facebookでは、プロダクション用iOSアプリのリリースに向けて2週間ごとにコードベースを安定させる必要があったため、オープンソース版も同じペースでリリースすることにしました。現在、Facebookのアプリの多くは、特にAndroidで週に1回出荷されています。私たちはマスターから毎週出荷するため、かなり安定した状態を保つ必要があります。そのため、2週間ごとのリリースサイクルは、もはや社内貢献者にとっても利益になりません。

リリース速度が速すぎて追いつくのが難しいというフィードバックをコミュニティから頻繁に耳にします。Expoのようなツールは、バージョンの急速な変更に対応するため、隔週のリリースをスキップする必要がありました。したがって、隔週のリリースがコミュニティに良いサービスを提供していなかったことは明らかです。

月次リリースを開始

新しい月次リリースサイクルと、先月安定化され、採用準備が整った2016年12月リリース、v0.40を発表できることを嬉しく思います。(iOSでネイティブモジュールのヘッダーを更新するのを忘れないでください)。

週末を避けたり、予期せぬ問題に対応するために数日ずれることはあるかもしれませんが、これからは各リリースが月の初めに利用可能になり、月末に正式リリースされると期待していただいて構いません。

最高のサポートを得るために当月のリリースを使用する

1月のリリース候補版(RC)が試せるようになっています。新機能はこちらで確認できます。

どのような変更が導入されるかを確認し、React Nativeの貢献者により良いフィードバックを提供するために、可能であれば常に当月のリリース候補を使用してください。各バージョンが月末にリリースされるまでに、そのバージョンに含まれる変更は2週間以上、Facebookのプロダクションアプリで出荷されています。

新しいreact-native-git-upgradeコマンドを使えば、アプリを簡単にアップグレードできます。

npm install -g react-native-git-upgrade
react-native-git-upgrade 0.41.0-rc.0

このよりシンプルなアプローチによって、コミュニティがReact Nativeの変更を追いやすくなり、新しいバージョンをできるだけ早く導入しやすくなることを願っています!

(この計画を立案したMartin Konicekと、それを実現したMike Grabowskiに感謝します)

Gitによるアップグレードの簡素化

·5分で読めます
Nicolas Cuillery
ZenikaのJavaScriptコンサルタント兼トレーナー

React Nativeの新しいバージョンへのアップグレードは困難でした。以前、このような画面を見たことがあるかもしれません。

これらの選択肢はどれも理想的ではありません。ファイルを上書きするとローカルの変更が失われます。上書きしないと最新のアップデートが適用されません。

本日、この問題を解決する新しいツールを紹介できることを誇りに思います。このツールは react-native-git-upgrade と呼ばれ、裏側でGitを使用して、可能な限り自動的にコンフリクトを解決します。

使い方

要件:Gitが PATH で利用可能である必要があります。プロジェクトがGitで管理されている必要はありません。

react-native-git-upgrade をグローバルにインストールします。

$ npm install -g react-native-git-upgrade

または、Yarn を使用する場合

$ yarn global add react-native-git-upgrade

その後、プロジェクトディレクトリ内で実行します。

$ cd MyProject
$ react-native-git-upgrade 0.38.0

注意: react-native の新しいバージョンをインストールするために「npm install」を実行しないでください。ツールが正しく機能するためには、古いプロジェクトテンプレートと新しいプロジェクトテンプレートを比較できる必要があります。上記の通り、まだ古いバージョンのままで、アプリフォルダ内で実行するだけです。

出力例

引数なしで react-native-git-upgrade を実行して、React Nativeの最新バージョンにアップグレードすることもできます。

AndroidとiOSのビルドファイルにおける変更を保持しようと試みるため、アップグレード後に react-native link を実行する必要はありません。

実装は、可能な限り介入が少なくなるように設計されています。一時ディレクトリにオンザフライで作成されるローカルGitリポジトリに完全に依存しています。プロジェクトのリポジトリ(使用しているVCSがGit、SVN、Mercurial、...または何も使用していないかにかかわらず)とは干渉しません。予期せぬエラーが発生した場合は、ソースが復元されます。

仕組み

重要なステップはGitパッチの生成です。このパッチには、アプリが使用しているバージョンと新しいバージョンの間でReact Nativeテンプレートに加えられたすべての変更が含まれています。

このパッチを取得するには、node_modules ディレクトリ内の react-native パッケージに埋め込まれているテンプレート(react-native init コマンドが使用するのと同じテンプレートです)からアプリを生成する必要があります。そして、現在のバージョンと新しいバージョンの両方でテンプレートからネイティブアプリが生成された後、Gitはプロジェクトに適応したパッチ(つまり、アプリ名を含むパッチ)を生成することができます。

[...]

diff --git a/ios/MyAwesomeApp/Info.plist b/ios/MyAwesomeApp/Info.plist
index e98ebb0..2fb6a11 100644
--- a/ios/MyAwesomeApp/Info.plist
+++ b/ios/MyAwesomeApp/Info.plist
@@ -45,7 +45,7 @@
<dict>
<key>localhost</key>
<dict>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
[...]

あとは、このパッチをソースファイルに適用するだけです。以前の react-native upgrade プロセスではわずかな違いでもプロンプトが表示されていましたが、Gitは3-wayマージアルゴリズムを使用して変更のほとんどを自動的にマージし、最終的に使い慣れた競合区切り文字を残します。

    13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
<<<<<<< ours
CODE_SIGN_IDENTITY = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/HockeySDK.embeddedframework",
"$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
);
=======
CURRENT_PROJECT_VERSION = 1;
>>>>>>> theirs
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
);

これらのコンフリクトは通常、理解しやすいものです。区切り文字 ours は「あなたのチーム」を表し、theirs は「React Nativeチーム」と見なすことができます。

なぜ新しいグローバルパッケージを導入するのか?

React NativeにはグローバルCLI(react-native-cli パッケージ)が付属しており、node_modules/react-native/local-cli ディレクトリに組み込まれているローカルCLIにコマンドを委譲します。

上記で述べたように、プロセスは現在のReact Nativeバージョンから開始する必要があります。もし実装をlocal-cliに組み込んでいたら、古いバージョンのReact Nativeを使用している場合、この機能を利用することはできなかったでしょう。例えば、この新しいアップグレードコードが0.38.0でしかリリースされていなかった場合、0.29.2から0.38.0にアップグレードすることはできなかったでしょう。

Gitに基づくアップグレードは開発者エクスペリエンスの大きな改善であり、誰もが利用できるようにすることが重要です。グローバルにインストールされる別のパッケージ react-native-git-upgrade を使用することで、プロジェクトがどのバージョンのReact Nativeを使用しているかにかかわらず、この新しいコードを今日から使用できます。

もう一つの理由は、最近のMartin KonicekによるYeomanの廃止です。パッチを作成するために古いテンプレートを評価できるよう、これらのYeomanの依存関係をreact-nativeパッケージに戻したくありませんでした。

試してフィードバックを提供してください

結論として、この機能を楽しんで、自由に改善を提案したり、問題を報告したり、特にプルリクエストを送信したりしてください。各環境は少しずつ異なり、各React Nativeプロジェクトも異なります。この機能をすべての人にとってうまく機能させるためには、皆さんのフィードバックが必要です。

ありがとうございます!

このすべてが可能になったのは、素晴らしい企業であるZenikaM6 Web(アーカイブ)のおかげです!心から感謝申し上げます!

Buttonの導入、Yarnによる高速インストール、そして公開ロードマップ

·3分で読めます
Héctor Ramos
Héctor Ramos
元Facebook デベロッパーアドボケイト

React Nativeで多くの作業が行われているため、何が起こっているのかを把握するのが難しいという声を多くの人から聞いています。現在進行中の作業を伝えるために、React Nativeのロードマップを公開しています。大まかに言うと、この作業は3つの優先順位に分けられます。

  • コアライブラリ。最も有用なコンポーネントとAPIに機能を追加します。
  • 安定性。基盤となるインフラストラクチャを改善し、バグを減らし、コード品質を向上させます。
  • 開発者エクスペリエンス。React Native開発者がより速く作業できるようにします。

ロードマップ上で価値があると思われる機能の提案がある場合は、Cannyをご覧ください。ここでは、新しい機能を提案したり、既存の提案について議論したりできます。

React Nativeの新機能

本日リリースされたReact Nativeバージョン0.37では、どのアプリにもタッチ可能なButtonを非常に簡単に追加できる新しいコアコンポーネントが導入されました。また、新しいYarnパッケージマネージャーのサポートも導入しており、アプリの依存関係を更新するプロセス全体が高速化されるはずです。

Buttonの導入

本日、すべてのプラットフォームで見栄えの良い基本的な<Button />コンポーネントを導入します。これは、私たちが最もよく受けるフィードバックの1つに対処するものです。React Nativeは、すぐに使えるボタンが付属していない数少ないモバイル開発ツールキットの1つです。

Simple Button on Android, iOS

<Button
onPress={onPressMe}
title="Press Me"
accessibilityLabel="Learn more about this Simple Button"
/>

経験豊富なReact Native開発者は、ボタンの作成方法を知っています。iOSではデフォルトの外観にTouchableOpacityを、Androidではリップル効果にTouchableNativeFeedbackを使用し、いくつかのスタイルを適用します。カスタムボタンの構築やインストールは特に難しくありませんが、私たちはReact Nativeを非常に簡単に学習できるようにすることを目指しています。コアに基本的なボタンを追加することで、初心者はボタンの書式設定やTouchableのニュアンスを学ぶのに時間を費やす代わりに、初日で素晴らしいものを開発できるようになります。

Buttonは、すべてのプラットフォームでうまく機能し、ネイティブに見えるように意図されているため、カスタムボタンが持つすべての機能はサポートしていません。これは優れた出発点ですが、既存のすべてのボタンを置き換えることを意図したものではありません。詳細については、実行可能な例が付属した新しいButtonドキュメントをご覧ください!

Yarnを使用したreact-native initの高速化

JavaScriptの新しいパッケージマネージャーであるYarnを使用して、react-native initを大幅に高速化できるようになりました。高速化を確認するには、yarnをインストールし、react-native-cliを1.2.0にアップグレードしてください。

$ npm install -g react-native-cli

新しいアプリを設定する際に「Using yarn」と表示されるはずです。

Using yarn

簡単なローカルテストでは、react-native init良好なネットワーク環境で約1分で完了しました(npm 3.10.8を使用した場合の約3分と比較して)。Yarnのインストールは任意ですが、強く推奨されます。

ありがとうございます!

このリリースに貢献してくださったすべての方々に感謝いたします。完全なリリースノートはGitHubで公開されています。2ダース以上のバグ修正と新機能のおかげで、React Nativeは皆様のおかげで常に改善され続けています。

0.36: Headless JS、Keyboard API、その他

·3分で読めます
Héctor Ramos
Héctor Ramos
元Facebook デベロッパーアドボケイト

本日、React Native 0.36 をリリースします。新機能の詳細については、こちらをお読みください。

Headless JS

Headless JSは、アプリがバックグラウンドにある間にJavaScriptでタスクを実行する方法です。たとえば、最新データの同期、プッシュ通知の処理、音楽の再生などに使用できます。現在のところ、Androidでのみ利用可能です。

まず、非同期タスクを専用のファイル(例: SomeTaskName.js)で定義します。

module.exports = async taskData => {
// Perform your task here.
};

次に、AppRegistry にタスクを登録します。

AppRegistry.registerHeadlessTask('SomeTaskName', () =>
require('SomeTaskName'),
);

Headless JSを使用するには、必要な時にサービスを開始できるように、いくつかのネイティブJavaコードを記述する必要があります。詳細については、新しいHeadless JSのドキュメントをご覧ください!

Keyboard API

オンスクリーンキーボードの操作がKeyboardでより簡単になりました。ネイティブのキーボードイベントをリッスンして、それらに反応できるようになりました。たとえば、アクティブなキーボードを閉じるには、単にKeyboard.dismiss()を呼び出すだけです。

import {Keyboard} from 'react-native';

// Hide that keyboard!
Keyboard.dismiss();

アニメーションによる除算

2つのアニメーション値を加算、乗算、モジュロで結合することは、すでにReact Nativeでサポートされています。バージョン0.36では、除算によって2つのアニメーション値を結合することが可能になりました。アニメーション値が計算のために他のアニメーション値を反転する必要があるケースがあります。例としては、スケールを反転させること(2倍 → 0.5倍)です。

const a = Animated.Value(1);
const b = Animated.divide(1, a);

Animated.spring(a, {
toValue: 2,
}).start();

baのスプリングアニメーションに従い、1 / aの値を生成します。

基本的な使用法は次のようになります。

<Animated.View style={{transform: [{scale: a}]}}>
<Animated.Image style={{transform: [{scale: b}]}} />
<Animated.View>

この例では、親の拡大・縮小が相殺されるため、内側の画像はまったく引き伸ばされません。さらに詳しく知りたい場合は、アニメーションガイドをご覧ください。

ダークステータスバー

新しいbarStyle値がStatusBarに追加されました:dark-content。この追加により、AndroidとiOSの両方でbarStyleを使用できるようになりました。動作は次のようになります。

  • default: プラットフォームのデフォルトを使用します(iOSではライト、Androidではダーク)。
  • light-content: 黒いテキストとアイコンを持つライトステータスバーを使用します。
  • dark-content: 白いテキストとアイコンを持つダークステータスバーを使用します。

...その他

上記は0.36で変更された内容のごく一部です。新機能、バグ修正、破壊的変更の全リストについては、GitHubのリリースノートをご確認ください。

ターミナルで次のコマンドを実行することで、0.36にアップグレードできます。

$ npm install --save react-native@0.36
$ react-native upgrade