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

React Nativeアプリの右から左へのレイアウトサポート

·8分で読めます
Mengjue (Mandy) Wang
Facebook ソフトウェアエンジニアインターン

アプリをApp Storeにリリースした後、国際化はオーディエンスの拡大に向けた次のステップです。世界中の20カ国以上、そして多くの人々が右から左へ記述する(RTL)言語を使用しています。したがって、彼らのためにアプリがRTLをサポートすることは不可欠です。

React NativeがRTLレイアウトをサポートするように改善されたことを発表できることを嬉しく思います。これは本日、react-nativeのマスターブランチで利用可能であり、次のRCであるv0.33.0-rcで利用可能になります。

これには、RNで使われているコアレイアウトエンジンであるcss-layoutやRNのコア実装、そして特定のOSS JSコンポーネントをRTLに対応させるための変更が含まれています。

本番環境でRTLサポートを実戦テストするため、最新バージョンの Facebook Ads Manager アプリ(初のクロスプラットフォーム100% RNアプリ)が、アラビア語とヘブライ語で、iOSAndroidの両方でRTLレイアウトをサポートして利用可能になりました。これらのRTL言語での表示は次のとおりです。

RTLサポートにおけるRNの概要変更点

css-layoutには、すでにレイアウトのstartendの概念があります。左から右へ記述する(LTR)レイアウトでは、startleftを意味し、endrightを意味します。しかし、RTLでは、startrightを意味し、endleftを意味します。これは、RNがstartendの計算に依存して、positionpaddingmarginを含む正しいレイアウトを計算できることを意味します。

さらに、css-layoutは、すでに各コンポーネントの方向をその親から継承するようにしています。これは、ルートコンポーネントの方向をRTLに設定するだけで、アプリ全体が反転することを意味します。

以下の図は、変更点の概要を示しています。

これらには以下のものが含まれます。

このアップデートにより、アプリでRTLレイアウトを許可すると、

  • すべてのコンポーネントのレイアウトが水平方向に反転します
  • RTL対応のOSSコンポーネントを使用している場合、一部のジェスチャーやアニメーションも自動的にRTLレイアウトになります
  • アプリを完全にRTL対応にするために、最小限の追加作業が必要になる場合があります

アプリをRTL対応にする

  1. RTLをサポートするには、まずRTL言語のバンドルをアプリに追加する必要があります。

    • iOSAndroidの一般的なガイドを参照してください。
  2. ネイティブコードの冒頭でallowRTL()関数を呼び出すことで、アプリのRTLレイアウトを許可します。このユーティリティは、アプリの準備ができたときにのみRTLレイアウトを適用するために提供されています。以下に例を示します。

    iOS

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. Androidの場合、AndroidManifest.xmlファイルの<application>要素にandroid:supportsRtl="true"を追加する必要があります。

これで、アプリを再コンパイルし、デバイスの言語をRTL言語(例:アラビア語やヘブライ語)に変更すると、アプリのレイアウトは自動的にRTLに変わるはずです。

RTL対応コンポーネントの記述

一般的に、ほとんどのコンポーネントはすでにRTL対応です。例えば、

  • 左横書きレイアウト
  • 右横書きレイアウト

ただし、注意すべきいくつかのケースがあり、それらにはI18nManagerが必要になります。I18nManagerには、アプリのレイアウトがRTLであるかどうかを判断する定数isRTLがあり、レイアウトに応じて必要な変更を加えることができます。

方向性のある意味を持つアイコン

コンポーネントにアイコンや画像がある場合、RNはソース画像を反転させないため、LTRレイアウトとRTLレイアウトで同じように表示されます。したがって、レイアウトスタイルに応じてこれらを反転させる必要があります。

  • 左横書きレイアウト
  • 右横書きレイアウト

方向に応じてアイコンを反転させる方法は2つあります。

  • 画像コンポーネントにtransformスタイルを追加する

    <Image
    source={...}
    style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
    />
  • または、方向に応じて画像ソースを変更する

    let imageSource = require('./back.png');
    if (I18nManager.isRTL) {
    imageSource = require('./forward.png');
    }
    return <Image source={imageSource} />;

ジェスチャーとアニメーション

AndroidおよびiOS開発において、RTLレイアウトに変更すると、ジェスチャーとアニメーションはLTRレイアウトと逆になります。現在、RNでは、ジェスチャーとアニメーションはRNコアコードレベルではなく、コンポーネントレベルでサポートされています。幸いなことに、SwipeableRowNavigationExperimentalなど、これらのコンポーネントの一部はすでにRTLをサポートしています。ただし、ジェスチャーを持つ他のコンポーネントは、手動でRTLをサポートする必要があります。

ジェスチャーRTLサポートを説明する良い例はSwipeableRowです。

ジェスチャーの例
// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
アニメーションの例
// SwipeableRow.js
_animateBounceBack(duration: number): void {
// ...
const swipeBounceBackDistance = IS_RTL ?
-RIGHT_SWIPE_BOUNCE_BACK_DISTANCE :
RIGHT_SWIPE_BOUNCE_BACK_DISTANCE;
this._animateTo(
-swipeBounceBackDistance,
duration,
this._animateToClosedPositionDuringBounce,
);
},

RTL対応アプリのメンテナンス

RTL互換アプリの初期リリース後も、新しい機能について繰り返し開発を行う必要があるでしょう。開発効率を向上させるために、I18nManagerは、テストデバイスの言語を変更することなく、より高速なRTLテストのためにforceRTL()関数を提供します。アプリにこのための簡単なスイッチを提供したいかもしれません。以下はRNTesterのRTL例からの例です。

<RNTesterBlock title={'Quickly Test RTL Layout'}>
<View style={styles.flexDirectionRow}>
<Text style={styles.switchRowTextView}>forceRTL</Text>
<View style={styles.switchRowSwitchView}>
<Switch
onValueChange={this._onDirectionChange}
style={styles.rightAlignStyle}
value={this.state.isRTL}
/>
</View>
</View>
</RNTesterBlock>;

_onDirectionChange = () => {
I18nManager.forceRTL(!this.state.isRTL);
this.setState({isRTL: !this.state.isRTL});
Alert.alert(
'Reload this page',
'Please reload this page to change the UI direction! ' +
'All examples in this app will be affected. ' +
'Check them out to see what they look like in RTL layout.',
);
};

新機能に取り組む際、このボタンを簡単に切り替えてアプリをリロードすることでRTLレイアウトを確認できます。利点は、テストのために言語設定を変更する必要がないことですが、次のセクションで説明するように、一部のテキスト配置は変更されません。したがって、リリース前にRTL言語でアプリをテストすることは常に良いアイデアです。

制限事項と将来の計画

RTLサポートはアプリのUXのほとんどをカバーするはずですが、現時点ではいくつかの制限があります。

  • テキストの配置の挙動がAndroidとiOSで異なる
    • iOSでは、デフォルトのテキスト配置はアクティブな言語バンドルに依存し、常に一方の側に揃えられます。Androidでは、デフォルトのテキスト配置はテキストコンテンツの言語に依存し、例えば英語は左揃え、アラビア語は右揃えになります。
    • 理論的には、これはプラットフォーム間で一貫性を保つべきですが、アプリを使用する人によっては、一方の挙動を好む場合があります。テキスト配置のベストプラクティスを見つけるためには、さらなるユーザーエクスペリエンス調査が必要かもしれません。
  • 「真の」左/右が存在しない

    前述の通り、JS側のleft/rightスタイルをstart/endにマッピングしており、RTLレイアウトの場合、コード内のすべてのleftは画面上で「右」になり、コード内のrightは画面上で「左」になります。これは、製品コードをあまり変更する必要がないため便利ですが、コード内で「真の左」または「真の右」を指定する方法がないことを意味します。将来的には、言語に関係なくコンポーネントが自身の方向を制御できるようにすることが必要になるかもしれません。

  • ジェスチャーとアニメーションのRTLサポートをより開発者フレンドリーにする

    現在、ジェスチャーとアニメーションをRTL互換にするには、まだプログラミングの労力が必要です。将来的には、ジェスチャーとアニメーションのRTLサポートをより開発者フレンドリーにする方法を見つけることが理想的です。

試してみる!

RTLサポートについてさらに理解するには、RNTester内のRTLExampleをチェックして、どのように機能するか教えてください!

最後までお読みいただきありがとうございます!React NativeのRTLサポートが、国際的なオーディエンス向けにアプリを成長させる助けとなることを願っています!

サンフランシスコミートアップのレポート

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

先週、私はZyngaのサンフランシスコオフィスで開催されたReact Native Meetupに参加する機会を得ました。約200人が参加し、近くでReact Nativeに興味を持っている他の開発者と出会うのに最適な場所となりました。

私は特に、Zynga、Netflix、Airbnbといった企業でReactとReact Nativeがどのように使われているかについて学ぶことに興味がありました。その夜のアジェンダは以下の通りでした。

  • Reactにおけるラピッドプロトタイピング
  • React NativeのためのAPI設計
  • ギャップを埋める:既存のコードベースでReact Nativeを使用する

しかし、まずイベントは簡単な紹介と最近のニュースの簡単な要約から始まりました。

お近くでこれらのミートアップが開催される場合は、ぜひ参加することをお勧めします!

ZyngaでのReactによる高速プロトタイピング

最初のニュースラウンドに続いて、この夜のホストであるZyngaによる簡単な紹介がありました。Abhishek Chadha氏は、モバイルで新しい体験を迅速にプロトタイプするためにReactをどのように使用しているかについて話し、Draw Somethingのようなアプリの簡単なプロトタイプをデモしました。彼らはReact Nativeと同様のアプローチを使用し、ブリッジを介してネイティブAPIへのアクセスを提供しています。これは、Abhishekがデバイスのカメラを使って観客の写真を撮り、その後誰かの頭に帽子を描いたときに実証されました。

NetflixでのReact Native向けAPI設計

次に、この夜の最初の特集講演です。NetflixのシニアソフトウェアエンジニアであるClarence Leung氏が、React Native向けAPI設計に関する講演を行いました。まず彼は、開発者が扱う可能性のある2つの主要なライブラリの種類について言及しました。それは、タブバーや日付ピッカーなどのコンポーネントと、カメラロールやアプリ内課金などのネイティブサービスへのアクセスを提供するライブラリです。React Nativeで使うライブラリを構築する際には、2つのアプローチがあります。

  • プラットフォーム固有のコンポーネントを提供する
  • AndroidとiOSの両方で同様のAPIを持つクロスプラットフォームライブラリ

それぞれのアプローチには独自の考慮事項があり、自分のニーズに最も適したものを決定するのはあなた次第です。

アプローチ #1

プラットフォーム固有のコンポーネントの例として、ClarenceはReact NativeコアのDatePickerIOSとDatePickerAndroidについて話しました。iOSでは、日付ピッカーはUIの一部としてレンダリングされ、既存のビューに簡単に埋め込むことができますが、Androidでは日付ピッカーはモーダルで表示されます。この場合は個別のコンポーネントを提供することが理にかなっています。

アプローチ #2

一方、写真ピッカーはAndroidとiOSで同様に扱われます。AndroidがiOSのように写真をセルフィーなどのフォルダにグループ化しないなど、若干の違いはありますが、それらは`if`文と`Platform`コンポーネントを使って簡単に処理できます。

どちらのアプローチを採用するにしても、APIサーフェスを最小限に抑え、アプリ固有のライブラリを構築することをお勧めします。たとえば、iOSのApp内課金フレームワークは、1回限りの消費型購入と、自動更新型サブスクリプションの両方をサポートしています。アプリが消費型購入のみをサポートする必要がある場合、クロスプラットフォームライブラリでサブスクリプションのサポートを削除しても問題ないかもしれません。

Clarence氏のトークの最後には、短いQ&Aセッションがありました。そこから出てきた興味深い情報の一つは、Netflixでこれらのライブラリのために書かれたReact Nativeコードの約80%が、AndroidとiOSの両方で共有されているということでした。

ギャップを埋める、既存のコードベースでのReact Nativeの使用

この夜最後の講演は、AirbnbのLeland Richardson氏によるものでした。講演は、既存のコードベースでReact Nativeを使用することに焦点を当てていました。私はReact Nativeを使って新しいアプリをゼロから書くのがどれほど簡単か知っていたので、Airbnbが既存のネイティブアプリにReact Nativeを導入した経験について聞くことに非常に興味がありました。

リーランド氏は、グリーンフィールドアプリとブラウンフィールドアプリについて語り始めました。グリーンフィールドとは、以前の作業を考慮する必要なくプロジェクトを開始することを意味します。これは、既存のプロジェクトの要件、開発プロセス、およびチームのさまざまなニーズを考慮する必要があるブラウンフィールドプロジェクトとは対照的です。

グリーンフィールドアプリで作業している場合、React Native CLIはAndroidとiOSの両方に単一のリポジトリを設定し、すべてが機能します。AirbnbでReact Nativeを使用する際の最初の課題は、AndroidとiOSアプリがそれぞれ独自のリポジトリを持っていたという事実でした。複数のリポジトリを持つ企業は、React Nativeを採用する前にいくつかのハードルを乗り越える必要があります。

これを回避するため、AirbnbはまずReact Nativeのコードベース用に新しいリポジトリを設定しました。彼らは継続的インテグレーションサーバーを使用して、AndroidとiOSのリポジトリをこの新しいリポジトリにミラーリングしました。テストが実行され、バンドルがビルドされた後、ビルドアーティファクトはAndroidとiOSのリポジトリに同期されます。これにより、モバイルエンジニアは開発環境を変更することなくネイティブコードで作業できます。モバイルエンジニアは、npmをインストールしたり、パッカーを実行したり、JavaScriptバンドルをビルドすることを覚えておく必要はありません。実際のReact Nativeコードを書くエンジニアは、React Nativeリポジトリで直接作業するため、コードをAndroidとiOS間で同期することを心配する必要はありません。

これにはいくつかの欠点があります。主に、アトミックな更新を配信できないことでした。ネイティブコードとJavaScriptコードの組み合わせが必要な変更には、3つの個別のプルリクエストが必要であり、これらはすべて慎重にマージする必要がありました。競合を避けるために、ビルドが開始されてからマスターが変更されている場合、CIは変更をAndroidおよびiOSリポジトリに戻すことを拒否します。これにより、コミット頻度が高い日(新しいリリースがカットされる日など)には長い遅延が発生する可能性がありました。

Airbnbはその後、モノレポアプローチに移行しました。幸いなことに、これはすでに検討されており、AndroidとiOSのチームがReact Nativeの使用に慣れると、彼らは喜んでモノレポへの移行を加速させました。

これにより、分割リポジトリのアプローチで抱えていた問題のほとんどが解決されました。Leland氏は、これがバージョン管理サーバーにより高い負荷をかけることになり、小規模な企業にとっては問題になる可能性があると指摘しました。

ナビゲーション問題

Leland氏の講演の後半は、私にとって重要なテーマであるReact Nativeにおけるナビゲーション問題に焦点を当てていました。彼は、React Nativeにおける数多くのナビゲーションライブラリ、すなわちファーストパーティとサードパーティの両方について語りました。NavigationExperimentalは有望に見えたが、彼らのユースケースには適していなかったと述べました。

実際、既存のナビゲーションライブラリのどれもブラウンフィールドアプリではうまく機能しないようです。ブラウンフィールドアプリでは、ナビゲーションの状態が完全にネイティブアプリによって所有される必要があります。たとえば、React Nativeビューが表示されている間にユーザーのセッションが期限切れになった場合、ネイティブアプリは必要に応じて引き継ぎ、ログイン画面を表示できる必要があります。

Airbnbはまた、移行の一環としてネイティブのナビゲーションバーをJavaScriptバージョンに置き換えることを避けたいと考えていました。その効果がぎこちなくなる可能性があるためです。当初はモーダル表示されるビューに限定していましたが、これはアプリ内でReact Nativeをより広く採用する際に明らかな問題となりました。

彼らは独自のライブラリが必要だと判断しました。そのライブラリは`airbnb-navigation`と呼ばれています。このライブラリはAirbnbのコードベースと強く結びついているため、まだオープンソース化されていませんが、年末までにリリースしたいと考えています。

ライブラリのAPIについて詳しくは触れませんが、以下にいくつかの重要なポイントを挙げます。

  • シーンを事前に登録する必要がある
  • 各シーンは独自のRCTRootView内に表示されます。これらは各プラットフォームでネイティブに表示されます(例:iOSではUINavigationControllerが使用されます)。
  • シーン内のメインのScrollViewScrollSceneコンポーネントでラップする必要があります。そうすることで、iOSでステータスバーをタップして一番上にスクロールするなどのネイティブの動作を活用できます。
  • シーン間のトランジションはネイティブで処理されるため、パフォーマンスについて心配する必要はありません。
  • Androidのバックボタンは自動的にサポートされます。
  • Navigator.ConfigというUIレスコンポーネントを介して、View Controllerベースのナビゲーションバーのスタイリングを活用できます。

また、留意すべきいくつかの考慮事項もあります。

  • ナビゲーションバーはネイティブコンポーネントであるため、JavaScriptで簡単にカスタマイズすることはできません。これは意図的なもので、ネイティブのナビゲーションバーを使用することがこのタイプのライブラリの厳しい要件だからです。
  • ScreenPropsはブリッジを介して送信されるたびにシリアライズ/デシリアライズする必要があるため、ここで大量のデータを送信する際には注意が必要です。
  • ナビゲーションの状態はネイティブアプリによって所有されているため(これもライブラリの厳しい要件)、Reduxのようなものでナビゲーションの状態を操作することはできません。

Leland氏の講演の後には質疑応答セッションも行われました。全体として、AirbnbはReact Nativeに満足しています。彼らはApp Storeを通さずに問題を修正するためにCode Pushを使用することに興味があり、エンジニアはLive Reloadを気に入っています。マイナーな変更のたびにネイティブアプリを再構築するのを待つ必要がないからです。

閉会の辞

イベントは、いくつかの追加のReact Nativeニュースで締めくくられました。

ミートアップは、コミュニティ内の他の開発者と出会い、学ぶ良い機会を提供します。今後もReact Nativeのミートアップに積極的に参加していきたいと思います。もしこれらのミートアップに参加される機会があれば、ぜひ私を見つけて、React Nativeをより良く活用するためにどうすればよいか教えてください!

より良いドキュメンテーションに向けて

·5分で読めます
Kevin Lacker
Facebook エンジニアリングマネージャー

優れた開発者体験には、優れたドキュメンテーションが不可欠です。良いドキュメンテーションを作成するには多くの労力がかかります。理想的なドキュメンテーションは、簡潔で、役立ち、正確で、完全で、そして楽しいものです。最近、私たちは皆さんのフィードバックに基づいてドキュメンテーションを改善するために懸命に取り組んできました。そこで、私たちが行った改善点の一部を皆さんと共有したいと思います。

インラインサンプル

新しいライブラリ、新しいプログラミング言語、または新しいフレームワークを学ぶとき、初めて少しのコードを書き、試してみて、それが機能するかどうかを確認し、それが実際に機能する...という美しい瞬間があります。あなたは何か本物を作り出したのです。私たちはその本能的な体験をドキュメンテーションに直接組み込みたいと考えました。このように。

import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';

class ScratchPad extends Component {
render() {
return (
<View style={{flex: 1}}>
<Text style={{fontSize: 30, flex: 1, textAlign: 'center'}}>
Isn't this cool?
</Text>
<Text style={{fontSize: 100, flex: 1, textAlign: 'center'}}>
👍
</Text>
</View>
);
}
}

AppRegistry.registerComponent('ScratchPad', () => ScratchPad);

Devin Abbottの協力を得たreact-native-web-playerモジュールを使用したこれらのインラインサンプルは、React Nativeの基本を学ぶための素晴らしい方法だと考えています。そして、新しいReact Native開発者向けのチュートリアルを、可能な限りこれらを使用するように更新しました。ぜひ試してみてください。もし、サンプルコードのほんの少しの部分を変更したらどうなるか、ずっと知りたかったなら、これは探求するのに本当に良い方法です。また、開発者ツールを構築していて、自分のサイトにライブのReact Nativeサンプルを表示したい場合は、react-native-web-playerがそれを簡単にします。

コアとなるシミュレーションエンジンは、Nicolas Gallagherreact-native-webプロジェクトによって提供されています。これは、TextViewのようなReact Nativeコンポーネントをウェブ上で表示する方法を提供します。コードベースの大部分を共有するモバイルおよびウェブ体験の構築に興味がある場合は、react-native-webをチェックしてみてください。

より良いガイド

React Nativeの一部の機能には複数の実現方法があり、より良いガイダンスを提供すべきだというフィードバックをいただきました。

新しいナビゲーションガイドでは、異なるアプローチを比較し、NavigatorNavigatorIOSNavigationExperimentalのうちどれを使用すべきかについてアドバイスしています。中期的には、これらのインターフェースの改善と統合に取り組んでいます。短期的には、より良いガイドが皆さんの生活を楽にすることを願っています。

ボタンのようなインターフェースを作成する基本的な方法と、タッチイベントを処理するさまざまな方法を簡潔にまとめた、タッチ処理に関する新しいガイドも作成しました。

もう一つ取り組んだ分野はFlexboxです。これには、Flexboxでレイアウトを処理する方法と、コンポーネントのサイズを制御する方法に関するチュートリアルが含まれています。また、地味ですが、うまくいけば役立つ、React Nativeでレイアウトを制御するすべてのプロパティのリストも含まれています。

はじめに

マシンにReact Native開発環境をセットアップし始めると、多くのもののインストールと設定を行う必要があります。インストールを本当に楽しくエキサイティングな体験にすることは困難ですが、少なくともできるだけ迅速かつ簡単に行えるようにすることはできます。

新しいGetting Startedワークフローを構築しました。これにより、開発用OSとモバイルOSを事前に選択でき、すべてのセットアップ手順を1つの簡潔な場所にまとめることができます。また、インストールプロセス全体を確認し、すべてが機能することを確認し、すべての決定ポイントに明確な推奨事項があることを確認しました。無邪気な同僚でテストした結果、これは改善であると確信しています。

また、既存のアプリにReact Nativeを統合するためのガイドにも取り組みました。Facebookアプリ自体のように、React Nativeを使用する最大規模のアプリの多くは、アプリの一部をReact Nativeで構築し、残りを通常の開発ツールで構築しています。このガイドが、より多くの人々がこの方法でアプリを構築するのを容易にすることを願っています。

皆様の協力が必要です

皆様のフィードバックは、私たちが何を優先すべきかを知る上で役立ちます。このブログ記事を読んで、「より良いドキュメント?ふん。Xのドキュメントはまだゴミじゃないか!」と思う人もいるでしょう。それは素晴らしいことです。私たちはそのエネルギーを必要としています。フィードバックの種類によって、私たちにフィードバックを伝える最善の方法は異なります。

説明が不正確だったり、実際に動作しないコードなど、ドキュメントに間違いを見つけた場合は、イシューを提出してください。「Documentation」というタグを付けて、適切な担当者に届けやすくしてください。

具体的な間違いではないが、ドキュメントの何かが根本的に分かりにくい場合は、GitHubのイシューにはあまり適していません。代わりに、助けが必要なドキュメントの分野についてCannyに投稿してください。これは、ガイドの執筆など、より一般的な作業を行う際に、私たちが優先順位を付けるのに役立ちます。

ここまで読んでいただき、React Nativeをご利用いただきありがとうございます!

React Native: 1年のレビュー

·2分で読めます
Martin Konicek
Facebook ソフトウェアエンジニア

React Native をオープンソース化してから1年が経ちました。数人のエンジニアによるアイデアから始まったこのフレームワークは、今やFacebook内外のプロダクトチームで使われるようになりました。本日F8で、MicrosoftがReact Native を Windows エコシステムに導入することを発表しました。これにより、開発者はWindows PC、Phone、XboxでReact Nativeを構築できるようになります。また、Visual Studio Code 用の React Native 拡張機能や CodePush といったオープンソースツールとサービスも提供され、開発者がWindowsプラットフォームで React Native アプリを作成するのに役立ちます。さらに、Samsung はハイブリッドプラットフォーム向けに React Native を構築しており、開発者は数百万台のスマートTV、モバイル、ウェアラブルデバイス向けアプリを開発できるようになります。私たちは、React Native 用 Facebook SDK もリリースしました。これにより、開発者はログイン、シェア、アプリ分析、グラフAPIといったFacebookのソーシャル機能をアプリに組み込むことがより簡単になります。この1年で、React Native は主要なすべてのプラットフォームでの開発方法を変えました。

これは壮大な道のりでしたが、まだ始まったばかりです。React Nativeが1年前にオープンソース化されてからどのように成長し、進化してきたか、その過程で直面したいくつかの課題、そして未来に目を向ける中で私たちが期待していることを振り返ります。

これは抜粋です。記事の全文はFacebook Codeでご覧ください。

React Nativeのパフォーマンスを深く掘り下げる

·2分で読めます
Pieter De Baets
Facebook ソフトウェアエンジニア

React Nativeを使うと、ReactとRelayの宣言型プログラミングモデルを使用してJavaScriptでAndroidおよびiOSアプリを構築できます。これにより、より簡潔で理解しやすいコード、コンパイルサイクルなしでの迅速な反復、複数プラットフォーム間でのコード共有の容易さが実現します。より迅速に出荷し、本当に重要な細部に集中して、アプリの外観と操作性を素晴らしいものにすることができます。パフォーマンスの最適化もこれの大部分を占めます。ここでは、React Nativeアプリの起動を2倍高速化した方法について説明します。

なぜ急ぐのか?

アプリの動作が高速になると、コンテンツがすぐに読み込まれ、人々がコンテンツとやり取りする時間が増え、スムーズなアニメーションがアプリを楽しく使用できるようにします。2011年クラスの携帯電話2Gネットワーク上で多数を占める新興市場では、パフォーマンスに焦点を当てることで、使えるアプリと使えないアプリの違いが生まれる可能性があります。

iOSおよびAndroidでReact Nativeをリリースして以来、リストビューのスクロールパフォーマンス、メモリ効率、UIの応答性、アプリの起動時間を改善してきました。起動はアプリの第一印象を左右し、フレームワークのあらゆる部分に負荷をかけるため、最もやりがいがあり、挑戦的な問題です。

これは抜粋です。記事の全文はFacebook Codeでお読みください。

ホットリローディングの導入

·9分で読めます
Martín Bigio
Instagram ソフトウェアエンジニア

React Nativeの目標は、可能な限り最高の開発者体験を提供することです。その大部分を占めるのが、ファイルを保存してから変更を確認できるまでの時間です。私たちの目標は、アプリが成長してもこのフィードバックループを1秒未満にすることです。

私たちは3つの主要な機能を通じてこの理想に近づきました。

  • 言語としてJavaScriptを使用することで、長いコンパイルサイクルタイムがなくなります。
  • Packagerと呼ばれるツールを実装しました。これはes6/flow/jsxファイルを、VMが理解できる通常のJavaScriptに変換します。これはサーバーとして設計されており、中間状態をメモリに保持することで高速な差分変更を可能にし、複数のコアを使用します。
  • 保存時にアプリをリロードするLive Reloadという機能を構築しました。

現時点では、開発者にとってのボトルネックは、アプリを再読み込みするのにかかる時間ではなく、アプリの状態を失うことです。一般的なシナリオは、起動画面から複数の画面を隔てた機能に取り組むことです。再読み込みするたびに、同じパスを何度もクリックして機能に戻る必要があり、サイクルが数秒長くなります。

ホットリロード

ホットリロードの背後にある考え方は、アプリを実行し続け、編集したファイルの新しいバージョンを実行時に注入することです。これにより、アプリの状態が失われず、特にUIを微調整している場合に便利です。

動画は百聞に一見に如かずです。Live Reload(現在)とHot Reload(新規)の違いをご覧ください。

よく見ると、レッドボックスから回復できること、また、以前は存在しなかったモジュールをフルリロードなしでインポートし始めることができることにお気づきでしょう。

注意:JavaScriptは非常にステートフルな言語であるため、ホットリロードを完全に実装することはできません。実際には、現在のセットアップは多くの一般的なユースケースでうまく機能しており、何か問題が発生した場合はいつでも完全にリロードできます。

ホットリロードは0.22から利用可能です。有効にするには

  • 開発者メニューを開きます
  • 「Enable Hot Reloading」をタップします

実装の概要

なぜそれが必要で、どのように使用するのかを見てきましたが、ここからが楽しい部分です:実際にどのように機能するのか。

ホットリロードは、ホットモジュールリプレースメント、略してHMRという機能に基づいて構築されています。これはwebpackによって最初に導入され、React Native Packager内に実装されました。HMRはPackagerにファイル変更を監視させ、薄いHMRランタイムにHMR更新を送信します。

要するに、HMRアップデートには変更されたJSモジュールの新しいコードが含まれています。ランタイムがそれらを受け取ると、古いモジュールのコードを新しいものに置き換えます。

HMR更新には、変更したいモジュールのコードだけでなく、もう少し多くのものが含まれています。なぜなら、それを置き換えるだけではランタイムが変更を認識するのに十分ではないからです。問題は、モジュールシステムがすでに更新したいモジュールのエクスポートをキャッシュしている可能性があることです。たとえば、次の2つのモジュールで構成されるアプリがあるとします。

// log.js
function log(message) {
const time = require('./time');
console.log(`[${time()}] ${message}`);
}

module.exports = log;
// time.js
function time() {
return new Date().getTime();
}

module.exports = time;

モジュールlogは、モジュールtimeから提供される現在の日付を含んだメッセージを出力します。

アプリがバンドルされると、React Nativeは各モジュールを__d関数を使用してモジュールシステムに登録します。このアプリでは、多くの__d定義の中にlogのためのものがあります。

__d('log', function() {
... // module's code
});

この呼び出しは、各モジュールのコードを匿名関数でラップします。これを一般的にファクトリ関数と呼びます。モジュールシステムランタイムは、各モジュールのファクトリ関数、それがすでに実行されたかどうか、およびその実行結果(エクスポート)を追跡します。モジュールが要求されると、モジュールシステムはすでにキャッシュされているエクスポートを提供するか、モジュールのファクトリ関数を初めて実行して結果を保存します。

では、アプリを起動してlogを要求するとします。この時点では、logtimeのファクトリ関数も実行されていないため、エクスポートはキャッシュされていません。その後、ユーザーがtimeを修正して日付をMM/DD形式で返すように変更します。

// time.js
function bar() {
const date = new Date();
return `${date.getMonth() + 1}/${date.getDate()}`;
}

module.exports = bar;

Packagerはtimeの新しいコードをランタイムに送信し(ステップ1)、最終的にlogがrequireされると、エクスポートされた関数が実行され、timeの変更が反映されます(ステップ2)。

次に、logのコードがトップレベルのrequireとしてtimeを必要とするとします。

const time = require('./time'); // top level require

// log.js
function log(message) {
console.log(`[${time()}] ${message}`);
}

module.exports = log;

logが要求されると、ランタイムはそのエクスポートとtimeのエクスポートをキャッシュします(ステップ1)。その後、timeが変更されても、HMRプロセスはtimeのコードを置き換えただけでは終了できません。もしそうした場合、logが実行されると、timeのキャッシュされたコピー(古いコード)で実行されてしまいます。

logtimeの変更を認識するには、依存するモジュールの1つがホットスワップされたため、キャッシュされたエクスポートをクリアする必要があります(ステップ3)。最後に、logが再度要求されると、そのファクトリ関数が実行され、timeを要求して新しいコードを取得します。

HMR API

React NativeのHMRは、hotオブジェクトを導入することでモジュールシステムを拡張します。このAPIはwebpackのAPIに基づいています。hotオブジェクトはacceptという関数を公開しており、モジュールがホットスワップされる必要があるときに実行されるコールバックを定義できます。例えば、timeのコードを次のように変更すると、timeを保存するたびにコンソールに「time changed」と表示されます。

// time.js
function time() {
... // new code
}

module.hot.accept(() => {
console.log('time changed');
});

module.exports = time;

このAPIを手動で使用する必要があるのはまれなケースのみであることに注意してください。ホットリロードは、最も一般的なユースケースではそのまま機能するはずです。

HMRランタイム

これまで見てきたように、ホットスワップされるモジュールを使用するモジュールがすでに実行されており、そのインポートがキャッシュされている場合、HMRの更新を受け入れるだけでは不十分なことがあります。例えば、ムービーアプリの例の依存関係ツリーに、MovieSearchビューとMovieScreenビューに依存する最上位のMovieRouterがあり、これらのビューは前の例のlogおよびtimeモジュールに依存しているとします。

ユーザーがムービー検索ビューにアクセスしたが、別のビューにはアクセスしていない場合、MovieScreenを除くすべてのモジュールはエクスポートをキャッシュしています。モジュールtimeに変更が加えられた場合、ランタイムはlogtimeの変更を認識できるように、logのエクスポートをクリアする必要があります。プロセスはそこで終わりません。ランタイムは、すべての親が受け入れられるまで、このプロセスを再帰的に繰り返します。つまり、logに依存するモジュールを取得し、それらを受け入れようとします。MovieScreenの場合、まだ必要とされていないため、終了できます。MovieSearchの場合、エクスポートをクリアし、親を再帰的に処理する必要があります。最後に、MovieRouterについても同様に行い、依存するモジュールがないためそこで終了します。

依存関係ツリーをたどるために、ランタイムはHMRアップデートでPackagerから逆依存関係ツリーを受け取ります。この例では、ランタイムは次のようなJSONオブジェクトを受け取ります。

{
modules: [
{
name: 'time',
code: /* time's new code */
}
],
inverseDependencies: {
MovieRouter: [],
MovieScreen: ['MovieRouter'],
MovieSearch: ['MovieRouter'],
log: ['MovieScreen', 'MovieSearch'],
time: ['log'],
}
}

Reactコンポーネント

Reactコンポーネントをホットリロードで動作させるのは少し困難です。問題は、コンポーネントの状態を失ってしまうため、単に古いコードを新しいコードに置き換えることができないことです。React Webアプリケーションの場合、Dan Abramovは、この問題を解決するためにwebpackのHMR APIを使用するbabelのトランスフォームを実装しました。簡単に言えば、彼のソリューションは、トランスフォーム時にすべてのReactコンポーネントのプロキシを作成することで機能します。プロキシはコンポーネントの状態を保持し、ライフサイクルメソッドを実際のコンポーネント(ホットリロードされるコンポーネント)に委譲します。

プロキシコンポーネントを作成するだけでなく、このtransformはReactにコンポーネントの再レンダリングを強制するコードでaccept関数も定義します。これにより、アプリの状態を失うことなくレンダリングコードをホットリロードできます。

React Nativeに付属のデフォルトのトランスフォーマーは、babel-preset-react-nativeを使用しており、これはwebpackを使用するReact Webプロジェクトでreact-transformを使用するのと同じ方法で設定されています。

Reduxストア

Reduxストアでホットリロードを有効にするには、webpackを使用するWebプロジェクトで行うのと同様にHMR APIを使用するだけです。

// configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from '../reducers';

export default function configureStore(initialState) {
const store = createStore(
reducer,
initialState,
applyMiddleware(thunk),
);

if (module.hot) {
module.hot.accept(() => {
const nextRootReducer = require('../reducers/index').default;
store.replaceReducer(nextRootReducer);
});
}

return store;
};

レデューサーを変更すると、そのレデューサーを受け入れるコードがクライアントに送信されます。するとクライアントは、レデューサーが自分自身を受け入れる方法を知らないことに気づき、参照しているすべてのモジュールを探してそれらを受け入れようとします。最終的に、フローは単一のストアであるconfigureStoreモジュールに到達し、これがHMR更新を受け入れます。

結論

ホットリロードの改善に協力することに興味がある方は、Dan Abramovのホットリロードの未来に関する投稿を読み、貢献することをお勧めします。例えば、Johny Daysは複数の接続されたクライアントで動作するようにする予定です。この機能の維持と改善は皆さんの手にかかっています。

React Nativeを使えば、アプリの構築方法を再考し、素晴らしい開発者体験を実現する機会があります。ホットリロードはパズルのピースの一つにすぎません。それをより良くするために、他にどんなクレイジーなハックができるでしょうか?

React Nativeアプリをアクセシブルにする

·2分で読めます
Georgiy Kassabli
Facebook ソフトウェアエンジニア

Web上のReactとモバイル上のReact Nativeの最近のリリースにより、開発者は製品を構築するための新しいフロントエンドフレームワークを手に入れました。堅牢な製品を構築する上で重要な側面の1つは、視覚障害やその他の障害を持つ人々を含む、誰でもそれを使用できることを保証することです。ReactおよびReact Native用のアクセシビリティAPIを使用すると、あらゆるReact駆動のエクスペリエンスを、視覚障害者や視覚に障がいのある人々のためのスクリーンリーダーなどの支援技術を使用する人でも利用できるようにすることができます。

この投稿では、React Nativeアプリに焦点を当てます。React Accessibility APIは、AndroidおよびiOS APIと同様の外観と操作感を持つように設計されています。これまでAndroid、iOS、またはWeb向けにアクセシブルなアプリケーションを開発した経験がある方なら、React AX APIのフレームワークと用語にすぐに慣れることができるはずです。例えば、UI要素をアクセシブルにし(したがって支援技術に公開し)、accessibilityLabelを使用して要素の文字列記述を提供できます。

<View accessible={true} accessibilityLabel=”This is simple view”>

Facebook自身のReact製プロダクトの一つである広告マネージャアプリを例に、React AX APIのもう少し踏み込んだ応用を見ていきましょう。

これは抜粋です。記事の全文はFacebook Codeでご覧いただけます。

React Native for Android: 最初のクロスプラットフォームReact Nativeアプリをどのように構築したか

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

今年の初めに、私たちはiOS版React Nativeを発表しました。React Nativeは、Web上のReactで開発者が慣れ親しんでいるもの、すなわち宣言型の自己完結型UIコンポーネントと迅速な開発サイクルをモバイルプラットフォームにもたらしつつ、ネイティブアプリケーションの速度、忠実度、そして操作感を維持します。本日、私たちはAndroid版React Nativeのリリースを喜んでお知らせします。

Facebookでは、1年以上にわたりReact Nativeを本番環境で使用してきました。ちょうど1年前、私たちのチームは広告マネージャアプリの開発に着手しました。私たちの目標は、Facebookに広告を出稿する何百万人もの人々が、外出先でアカウントを管理し、新しい広告を作成できる新しいアプリを作成することでした。これは、Facebook初の完全なReact Nativeアプリであるだけでなく、初のクロスプラットフォームアプリにもなりました。この投稿では、私たちがこのアプリをどのように構築したか、React Nativeがどのようにして私たちの開発を加速させたか、そして私たちが学んだ教訓を皆さんと共有したいと思います。

これは抜粋です。残りの記事は Facebook Code でお読みください。

React Native: モダンなウェブ技術をモバイルへ

·3分で読めます
Tom Occhino
Facebook エンジニアリングマネージャー

2年前、私たちはReactを世に送り出しました。それ以来、Facebook内外で目覚ましい成長を遂げています。今日では、誰も強制されているわけではありませんが、Facebookの新しいウェブプロジェクトは、何らかの形でReactを使用して構築されるのが一般的で、業界全体で広く採用されています。エンジニアは、製品の開発により多くの時間を費やし、フレームワークとの格闘に費やす時間を減らすことができるため、毎日Reactを使用することを選択しています。しかし、Reactを使ってしばらく開発を続けて初めて、私たちはその真の強力さに気づき始めました。

Reactは、アプリケーションを個々のコンポーネントに分解することを強制します。それぞれのコンポーネントは、単一のビューを表します。これらのコンポーネントにより、製品のイテレーションが容易になります。なぜなら、アプリケーションの一部を変更するためにシステム全体を頭に入れておく必要がないからです。さらに重要なのは、ReactがDOMの変異的で命令的なAPIを宣言的なAPIでラップすることで、抽象化レベルを高め、プログラミングモデルを簡素化している点です。Reactを使って構築すると、コードははるかに予測可能になることがわかりました。この予測可能性により、自信を持ってより迅速にイテレーションを進めることができ、その結果、アプリケーションの信頼性が大幅に向上します。さらに、Reactで構築されたアプリケーションは、スケーリングが容易になるだけでなく、チームの規模自体もスケーリングしやすくなることがわかりました。

ウェブの迅速なイテレーションサイクルと相まって、Facebook.comの多くのコンポーネントを含む、素晴らしい製品をReactで構築することができました。さらに、大規模なデータ取得を大幅に簡素化できるRelayのような、React上に素晴らしいJavaScriptフレームワークも構築しました。もちろん、ウェブは話の一部にすぎません。Facebookには、AndroidおよびiOSアプリも広く使用されており、これらはバラバラで独自の技術スタックの上に構築されています。複数のプラットフォーム上でアプリを構築しなければならないことは、当社のエンジニアリング組織を二分してしまいましたが、ネイティブモバイルアプリケーション開発を困難にしている要因はそれだけではありません。

これは抜粋です。残りの記事はFacebook Codeでお読みください。