本文へスキップ

2018年のReact Nativeの現状

読み時間5分
Sophie Alpert
FacebookのReactエンジニアリングマネージャー

最後にReact Nativeに関する状況報告を発表してからしばらく経ちました。

Facebookでは、これまで以上に多くの重要なプロジェクトでReact Nativeを使用しています。最も人気のある製品の1つにマーケットプレイスがあり、これはアプリのトップレベルタブの1つであり、毎月8億人が使用しています。2015年の作成以来、アプリのさまざまな部分全体に100を超えるフルスクリーンビューを含む、マーケットプレイス全体がReact Nativeで構築されてきました。

アプリの多くの新しい部分にもReact Nativeを使用しています。先月のF8基調講演をご覧になった方は、献血、危機対応、プライバシーショートカット、ウェルネスクリックをご存知でしょう - これらはすべてReact Nativeで構築された最近の機能です。そして、メインのFacebookアプリ以外のプロジェクトでもReact Nativeを使用しています。新しいOculus Go VRヘッドセットには、完全にReact Nativeで構築されたコンパニオンモバイルアプリが含まれており、ヘッドセット自体で多くのエクスペリエンスを強化するReact VRは言うまでもありません。

当然のことながら、アプリの構築には他の多くのテクノロジーも使用しています。LithoComponentKitは、アプリで広く使用している2つのライブラリです。どちらも、ネイティブ画面を構築するためのReactのようなコンポーネントAPIを提供します。React Nativeですべてのテクノロジーを置き換えることが目標だったことはありません - React Native自体の改善に重点を置いていますが、インスタントリロードをJavaScript以外のコードにも導入するなど、他のチームがReact Nativeからアイデアを借りているのを見るのが大好きです。

アーキテクチャ

2013年にReact Nativeプロジェクトを開始したとき、非同期、シリアライズ可能、バッチ処理可能なJavaScriptとネイティブ間の単一の「ブリッジ」を持つように設計しました。React DOMがReact状態の更新を、document.createElement(attrs).appendChild()などのDOM APIへの命令的な変更呼び出しに変換するのと同じように、React Nativeは、[["createView", attrs], ["manageChildren", ...]]のような実行する必要がある変更をリストする単一のJSONメッセージを返すように設計されました。このシステム全体は、同期応答の取得に依存せず、リスト内のすべてをJSONに完全にシリアライズして元に戻すことができるように設計されました。これは、柔軟性を提供してくれたためです。このアーキテクチャの上に、WebSocket接続を介してすべてのJavaScriptコードを非同期に実行するChromeデバッグなどのツールを構築することができました。

過去5年間で、これらの最初の原則により、一部の機能の構築が難しくなったことがわかりました。非同期ブリッジは、同期的な回答を期待する多くのネイティブAPIにJavaScriptロジックを直接統合できないことを意味します。ネイティブ呼び出しをキューイングするバッチ処理ブリッジは、React Nativeアプリがネイティブに実装された関数に呼び出しを行うのが難しくなります。そして、シリアライズ可能なブリッジは、2つの世界間でメモリを直接共有するのではなく、不要なコピーを意味します。完全にReact Nativeで構築されたアプリでは、これらの制限は通常許容範囲内です。しかし、React Nativeと既存のアプリコードとの複雑な統合を行うアプリでは、これらは不満の原因となります。

フレームワークをより柔軟にし、ハイブリッドJavaScript/ネイティブアプリでネイティブインフラストラクチャとより適切に統合するために、React Nativeの大規模な再アーキテクチャに取り組んでいます。このプロジェクトでは、過去5年間で学んだことを適用し、アーキテクチャをより現代的なものへと段階的に移行します。React Nativeの内部の多くを書き直していますが、ほとんどの変更は内部で行われています。既存のReact Nativeアプリは、ほとんどまたはまったく変更を加えることなく動作し続けます。

React Nativeをより軽量にし、既存のネイティブアプリにより適したものにするために、この再アーキテクチャには3つの主要な内部変更があります。まず、スレッドモデルを変更しています。各UI更新が3つの異なるスレッドで作業を実行する必要がある代わりに、高優先度の更新に対して任意のスレッドでJavaScriptに同期的に呼び出すことが可能になります。同時に、応答性を維持するために低優先度の作業をメインスレッドから離れたままにすることができます。次に、複数のレンダリング優先順位を許可し、非同期データ処理を簡素化するために、非同期レンダリング機能をReact Nativeに組み込んでいます。最後に、ブリッジを簡素化して、より高速で軽量にします。ネイティブとJavaScript間の直接呼び出しはより効率的であり、クロス言語スタックトレースのようなデバッグツールの構築が容易になります。

これらの変更が完了すると、より緊密な統合が可能になります。現在、複雑なハックを行わずに、ネイティブナビゲーションとジェスチャー処理、またはUICollectionViewやRecyclerViewのようなネイティブコンポーネントを組み込むことはできません。スレッドモデルに対する変更後、このような機能の構築は簡単になります。

この作業が完了に近づいたら、今年後半にもう少し詳細を発表します。

コミュニティ

Facebook内のコミュニティに加えて、Facebook外のReact Nativeユーザーとコラボレーターの活気のあるコミュニティがあることを嬉しく思っています。React Nativeユーザーへのより良いサービスと、プロジェクトへのコントリビューションを容易にすることで、React Nativeコミュニティをよりサポートしたいと考えています。

アーキテクチャの変更によってReact Nativeが他のネイティブインフラストラクチャとよりクリーンに相互運用できるようになるのと同様に、VMとバンドラの交換可能性を含め、JavaScriptエコシステムにより適するように、JavaScript側のReact Nativeをスリムにする必要があります。破壊的な変更のペースについていくのが難しいことを認識しているので、メジャーリリースを少なくする方法を見つけたいと考えています。最後に、スタートアップの最適化など、私たちの専門知識がまだ文書化されていないトピックについて、より徹底的なドキュメントを求めているチームもあることを知っています。来年中には、これらの変更の一部が見られるでしょう。

React Nativeを使用している場合、あなたは私たちのコミュニティの一員です。React Nativeをどのように改善できるか教えてください。

React Nativeはモバイル開発者のツールボックスの中の1つのツールにすぎませんが、私たちが強く信じているツールであり、過去1年間で500人以上の貢献者からの2500以上のコミットによって、毎日改善されています。

React NativeでのTypeScriptの使用

読み時間8分
Ash Furrow
Artsyのソフトウェアエンジニア

JavaScript!みんな大好きですよね。でも、データ型も好きな人もいますよね。についてです。幸い、JavaScriptにより強力な型を追加するオプションが存在します。私の好みはTypeScriptですが、React NativeはFlowを標準でサポートしています。どちらが良いかは好みによって異なりますが、それぞれJavaScriptに型の魔法を追加する独自の方式を持っています。今日は、React NativeアプリでTypeScriptを使用する方法を見ていきます。

この記事では、MicrosoftのTypeScript-React-Native-Starterリポジトリをガイドとして使用します。

更新:この記事が書かれてから、さらに簡単になりました。この記事で説明されているすべての設定は、1つのコマンドを実行するだけで置き換えられます。

npx react-native init MyAwesomeProject --template react-native-template-typescript

ただし、BabelのTypeScriptサポートにはいくつかの制限があり、上記のブログ記事で詳細に説明されています。この記事で説明されている手順はまだ機能しており、Artsyは依然としてreact-native-typescript-transformerを本番環境で使用していますが、React NativeとTypeScriptをすぐに使い始める最速の方法は、上記のコマンドを使用することです。必要に応じて後で切り替えることができます。

いずれにせよ、楽しんでください!元のブログ記事は以下に続きます。

前提条件

複数の異なるプラットフォームで開発し、いくつかの異なる種類のデバイスをターゲットにしている可能性があるため、基本的な設定には時間がかかる場合があります。最初に、TypeScriptなしでプレーンなReact Nativeアプリを実行できることを確認してください。React Native Webサイトの手順に従って開始してください。デバイスまたはエミュレータにデプロイできた場合は、TypeScript React Nativeアプリを開始する準備ができました。

Node.jsnpm、およびYarnも必要です。

初期化

通常のReact Nativeプロジェクトのスキャフォールディングを試したら、TypeScriptの追加を開始する準備ができました。早速やってみましょう。

react-native init MyAwesomeProject
cd MyAwesomeProject

TypeScriptの追加

次のステップは、プロジェクトにTypeScriptを追加することです。次のコマンドは、

  • プロジェクトにTypeScriptを追加します。
  • React Native TypeScript Transformerをプロジェクトに追加します。
  • 空のTypeScript設定ファイル(後で設定します)を初期化します。
  • 空のReact Native TypeScript Transformer設定ファイル(後で設定します)を追加します。
  • ReactとReact Nativeの型定義を追加します。

それでは、実行してみましょう。

yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native

tsconfig.jsonファイルには、TypeScriptコンパイラのすべての設定が含まれています。上記のコマンドによって作成されたデフォルトはほとんど問題ありませんが、ファイルを開いて次の行のコメントを外します。

{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}

rn-cli.config.jsファイルには、React Native TypeScript Transformerの設定が含まれています。このファイルを開き、次を追加します。

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

TypeScriptへの移行

生成されたApp.js__tests_/App.jsファイルをApp.tsxに名前変更します。index.js.js拡張子を使用する必要があります。すべての新しいファイルは.tsx拡張子(JSXを含まない場合は.ts)を使用する必要があります。

今アプリを実行しようとすると、object prototype may only be an object or nullのようなエラーが発生します。これは、Reactからのデフォルトエクスポートと同一行での名前付きエクスポートのインポートに失敗したことが原因です。App.tsxを開き、ファイルの先頭にあるインポートを変更します。

-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';

これの一部は、BabelとTypeScriptがCommonJSモジュールと相互運用する方法の違いによるものです。将来的には、両者は同じ動作で安定します。

この時点で、React Nativeアプリを実行できるはずです。

TypeScriptテストインフラストラクチャの追加

React NativeにはJestが付属しているため、TypeScriptを使用してReact Nativeアプリをテストするには、devDependenciests-jestを追加する必要があります。

yarn add --dev ts-jest

次に、package.jsonを開き、次のjestフィールドを置き換えます。

{
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
}
}

これにより、Jestはts-jestを使用して.ts.tsxファイルを実行するように設定されます。

依存関係の型宣言のインストール

TypeScriptで最高のエクスペリエンスを得るには、型チェッカーが依存関係の形状とAPIを理解する必要があります。一部のライブラリは、基盤となるJavaScriptの形状を記述できる.d.tsファイル(型宣言/型定義ファイル)を使用してパッケージを公開します。他のライブラリの場合は、@types/npmスコープで適切なパッケージを明示的にインストールする必要があります。

たとえば、ここでは、Jest、React、React Native、およびReact Test Rendererの型が必要です。

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

これらの宣言ファイルパッケージは、開発中にのみこれらの依存関係を使用するReact Nativeアプリであるため、dev依存関係に保存しました。ライブラリをNPMに公開する場合は、これらの型依存関係の一部を通常の依存関係として追加する必要がある場合があります。

.d.tsファイルの取得の詳細については、こちらをご覧ください。

その他のファイルの無視

ソース管理のために、.jestフォルダの無視を開始する必要があります。gitを使用している場合は、.gitignoreファイルにエントリを追加するだけで済みます。

# Jest
#
.jest/

チェックポイントとして、ファイルをバージョン管理にコミットすることを検討してください。

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

コンポーネントの追加

アプリにコンポーネントを追加しましょう。Hello.tsxコンポーネントを作成してみましょう。これは教育的なコンポーネントであり、実際にアプリに記述するようなものではありませんが、React NativeでTypeScriptを使用する方法を示す、些細ではないものです。

componentsディレクトリを作成し、次の例を追加します。

// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export interface Props {
name: string;
enthusiasmLevel?: number;
}

interface State {
enthusiasmLevel: number;
}

export class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

if ((props.enthusiasmLevel || 0) <= 0) {
throw new Error(
'You could be a little more enthusiastic. :D',
);
}

this.state = {
enthusiasmLevel: props.enthusiasmLevel || 1,
};
}

onIncrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel + 1,
});
onDecrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel - 1,
});
getExclamationMarks = (numChars: number) =>
Array(numChars + 1).join('!');

render() {
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello{' '}
{this.props.name +
this.getExclamationMarks(this.state.enthusiasmLevel)}
</Text>

<View style={styles.buttons}>
<View style={styles.button}>
<Button
title="-"
onPress={this.onDecrement}
accessibilityLabel="decrement"
color="red"
/>
</View>

<View style={styles.button}>
<Button
title="+"
onPress={this.onIncrement}
accessibilityLabel="increment"
color="blue"
/>
</View>
</View>
</View>
);
}
}

// styles
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});

すごい!たくさんありますが、分解してみましょう。

  • divspanh1などのHTML要素をレンダリングする代わりに、ViewButtonなどのコンポーネントをレンダリングしています。これらは、さまざまなプラットフォームで動作するネイティブコンポーネントです。
  • スタイルは、React Nativeが提供するStyleSheet.create関数を使用して指定されます。Reactのスタイルシートを使用すると、Flexboxを使用してレイアウトを制御し、CSSに似た他の構成を使用してスタイルを制御できます。

コンポーネントテストの追加

コンポーネントができたので、テストしてみましょう。

テストランナーとしてJestを既にインストールしています。コンポーネントのスナップショットテストを作成するので、スナップショットテストに必要なアドオンを追加しましょう。

yarn add --dev react-addons-test-utils

次に、componentsディレクトリに__tests__フォルダを作成し、Hello.tsxのテストを追加します。

// components/__tests__/Hello.tsx
import React from 'react';
import renderer from 'react-test-renderer';

import {Hello} from '../Hello';

it('renders correctly with defaults', () => {
const button = renderer
.create(<Hello name="World" enthusiasmLevel={1} />)
.toJSON();
expect(button).toMatchSnapshot();
});

テストが初めて実行されると、レンダリングされたコンポーネントのスナップショットが作成され、components/__tests__/__snapshots__/Hello.tsx.snapファイルに保存されます。コンポーネントを変更した場合は、スナップショットを更新し、意図しない変更がないか確認する必要があります。React Nativeコンポーネントのテストの詳細については、こちらをご覧ください。

次のステップ

公式のReactチュートリアルと状態管理ライブラリReduxを確認してください。これらのリソースは、React Nativeアプリを作成する際に役立ちます。さらに、Web上のReactとReact Nativeの両方をサポートする、TypeScriptで完全に記述されたコンポーネントライブラリであるReactXPも検討することをお勧めします。

より型安全なReact Native開発環境で楽しんでください!

React Nativeで構築 - Build.comアプリ

·読み時間5分
Garrett McCullough
シニアモバイルエンジニア

カリフォルニア州チコに本社を置くBuild.comは、住宅改修用品の大手オンライン小売業者の1つです。チームは18年間、強力なWeb中心のビジネスを行っており、2015年にモバイルアプリについて考え始めました。小規模なチームと限られたネイティブの経験では、独自のAndroidとiOSアプリを構築することは現実的ではありませんでした。そこで、非常に新しいReact Nativeフレームワークに賭けることにしました。最初のコミットは2015年8月12日、React Native v0.8.0を使用していました!2016年10月15日に両方のApp Storeでライブになりました。過去2年間、アプリのアップグレードと拡張を続けてきました。現在はReact Nativeバージョン0.53.0を使用しています。

アプリはhttps://www.build.com/appで確認できます。

機能

当社のアプリはフル機能を備えており、eコマースアプリに期待されるすべての機能が含まれています。製品リスト、検索とソート、複雑な製品の設定機能、お気に入りなどです。標準的なクレジットカード決済方法に加え、PayPalとApple Pay(iOSユーザー向け)も受け付けています。

期待できないかもしれないいくつかの優れた機能を以下に示します。

  1. 約40製品で90種類の仕上げが可能な3Dモデル
  2. 拡張現実(AR)により、ユーザーは照明器具や蛇口が自宅でどのように見えるかを98%のサイズ精度で確認できます。Build.com React Nativeアプリは、Apple App StoreでARショッピングとして紹介されています!ARは現在、AndroidとiOSで使用できます!
  3. プロジェクトのさまざまな段階で買い物リストを作成し、選択内容について共同作業できる共同プロジェクト管理機能

ARを使用した没入型ショッピングの次の段階など、アプリのエクスペリエンスをさらに向上させる多くの新しくエキサイティングな機能に取り組んでいます。

開発ワークフロー

Build.comでは、各開発者が自分に最適なツールを選択できます。

  • IDEには、Atom、IntelliJ、VS Code、Sublime、Eclipseなどがあります。
  • 単体テストでは、開発者は新しいコンポーネントのJest単体テストを作成する責任があり、jest-coverage-ratchetを使用してアプリの古い部分のテストカバレッジを向上させる取り組みに取り組んでいます。
  • Jenkinsを使用してベータ版とリリース候補を構築します。このプロセスは私たちにとってうまく機能しますが、リリースノートやその他の成果物を作成するには依然として多くの作業が必要です。
  • 統合テストには、デスクトップ、モバイル、Webで動作するテスターの共有プールが含まれます。自動化エンジニアは、JavaとAppiumを使用して自動統合テストスイートを構築しています。
  • ワークフローのその他の部分には、詳細なeslint設定、テストに必要なプロパティを強制するカスタムルール、違反する変更をブロックするプッシュ前フックなどがあります。

アプリで使用されているライブラリ

Build.comアプリは、Redux、Moment、Numeral、Enzyme、そしていくつかのReact Nativeブリッジモジュールを含む多くの一般的なオープンソースライブラリに依存しています。また、放棄されたか、カスタム機能が必要だったためにフォークされた、いくつかのフォークされたオープンソースライブラリも使用しています。簡単に数えると、約115個のJavaScriptとネイティブの依存関係があります。使用されていないライブラリを削除するツールを探求したいと思います。

現在、TypeScriptによる静的型付けを追加しており、オプショナルチェイニングについても検討しています。これらの機能は、依然として発生しているいくつかのバグの種類の解決に役立つ可能性があります。

  • 間違った型データ
  • オブジェクトに期待したものが含まれていなかったため未定義であるデータ

オープンソースへの貢献

オープンソースに大きく依存しているため、私たちのチームはコミュニティへの貢献に尽力しています。Build.comでは、チームが構築したライブラリをオープンソース化し、使用しているライブラリへの貢献を奨励しています。

いくつかのReact Nativeライブラリをリリースし、メンテナンスしています。

  • react-native-polyfill
  • react-native-simple-store
  • react-native-contact-picker

また、ReactとReact Native、react-native-schemes-managerreact-native-swipeablereact-native-galleryreact-native-view-transformerreact-native-navigationなど、多くのライブラリにも貢献しています。

私たちの取り組み

過去数年で、React Nativeとそのエコシステムは大きく成長しました。初期の頃は、React Nativeのあらゆるバージョンがいくつかのバグを修正する一方で、さらに多くのバグを導入しているように見えました。たとえば、AndroidでのリモートJSデバッグは数ヶ月間機能しませんでした。ありがたいことに、2017年には状況がはるかに安定しました。

私たちの大きな課題の一つは、ナビゲーションライブラリです。長い間、Expoのex-navライブラリを使用していました。それはうまく機能しましたが、最終的に非推奨となりました。しかし、当時、私たちは機能開発の真っ只中にあったため、ナビゲーションライブラリを変更する時間はありませんでした。そのため、ライブラリをフォークし、React 16とiPhone Xをサポートするように修正する必要がありました。最終的にreact-native-navigationに移行することができ、それが継続的にサポートされることを願っています。

ブリッジモジュール

もう一つの大きな課題は、ブリッジモジュールです。最初に始めたとき、多くの重要なブリッジがありませんでした。私のチームメイトの1人が、アプリでAndroidの連絡先ピッカーにアクセスする必要があったため、react-native-contact-pickerを作成しました。また、React Native内部の変更によって壊れたブリッジも多く見てきました。たとえば、React Native v40で破壊的な変更があり、アプリをアップグレードしたとき、まだ更新されていない3つか4つのライブラリを修正するためのPRを送信しなければなりませんでした。

今後の展望

React Nativeが成長を続けるにつれて、コミュニティへの要望は次のとおりです。

  • ナビゲーションライブラリの安定化と改善
  • React Nativeエコシステム内のライブラリに対するサポートの維持
  • ネイティブライブラリとブリッジモジュールをプロジェクトに追加する際のエクスペリエンスの向上

React Nativeコミュニティの企業や個人は、私たち全員が使用するツールの改善に時間と労力を費やしてくれています。オープンソースに参加したことがない場合は、使用しているライブラリのコードまたはドキュメントの改善を検討してみてください。始めるのに役立つ記事はたくさんあり、思っているよりもずっと簡単かもしれません!

React Native用の<InputAccessoryView>の構築

·読了時間6分
Peter Argany
Facebookソフトウェアエンジニア

モチベーション

3年前、React Nativeから入力アクセサリビューをサポートするためのGitHub issueが開設されました。

その後、数え切れないほどの「+1」、さまざまな回避策があり、この問題に対するRNへの具体的な変更はゼロでした - 今日まで。iOSから始め、ネイティブ入力アクセサリビューにアクセスするためのAPIを公開しています。そして、その構築方法を共有できることを嬉しく思います。

背景

入力アクセサリビューとは正確には何でしょうか?Appleの開発者ドキュメントを読むと、レシーバーがファーストレスポンダーになったときに、システムキーボードの上部に固定できるカスタムビューであることがわかります。UIResponderから継承するものは何でも、.inputAccessoryViewプロパティを読み書きとして再宣言し、ここでカスタムビューを管理できます。レスポンダーインフラストラクチャはビューをマウントし、システムキーボードと同期状態を保ちます。ドラッグやタップなど、キーボードを閉じるジェスチャは、フレームワークレベルで入力アクセサリビューに適用されます。これにより、iMessageやWhatsAppなどのトップレベルのメッセージングアプリに不可欠な機能である、インタラクティブなキーボードの閉じ方を備えたコンテンツを構築できます。

ビューをキーボードの上部に固定するための一般的なユースケースは2つあります。1つ目は、Facebookコンポーザーの背景ピッカーのようなキーボードツールバーを作成することです。

このシナリオでは、キーボードはテキスト入力フィールドにフォーカスされており、入力アクセサリビューは追加のキーボード機能を提供するために使用されます。この機能は、入力フィールドの種類に合わせてコンテキスト化されます。マッピングアプリケーションでは住所候補、テキストエディターではリッチテキストフォーマットツールになる可能性があります。


このシナリオでは、<InputAccessoryView>を所有するObjective-C UIResponderは明確である必要があります。<TextInput>がファーストレスポンダーになり、内部的にはUITextViewまたはUITextFieldのインスタンスになります。

2番目の一般的なシナリオは、スティッキーテキスト入力です。

ここでは、テキスト入力は実際に入力アクセサリビュー自体の一部です。これは、メッセージングアプリケーションで一般的に使用され、以前のメッセージのスレッドをスクロールしながらメッセージを作成できます。


この例では、<InputAccessoryView>を誰が所有しているのでしょうか?UITextViewまたはUITextFieldでも良いのでしょうか?テキスト入力は内部に入力アクセサリビューにあるため、循環依存関係のように聞こえます。この問題を解決するだけでも、別のブログ投稿になります。ネタバレ:所有者は、手動でbecomeFirstResponderするように指示する汎用的なUIViewサブクラスです。

API設計

これで、<InputAccessoryView>とは何か、そしてどのように使用したいかがわかりました。次のステップは、両方のユースケースに適しており、<TextInput>などの既存のReact Nativeコンポーネントと連携して動作するAPIを設計することです。

キーボードツールバーの場合、考慮すべき点がいくつかあります。

  1. 任意の汎用的なReact Nativeビュー階層を<InputAccessoryView>に持ち上げることができるようにしたいです。
  2. この汎用的な独立したビュー階層がタッチを受け入れ、アプリケーションの状態を操作できるようにしたいです。
  3. <InputAccessoryView>を特定の<TextInput>にリンクしたいです。
  4. コードを複製せずに、複数のテキスト入力間で<InputAccessoryView>を共有できるようにしたいです。

Reactポータルと同様の概念を使用して、#1を実現できます。この設計では、レスポンダーインフラストラクチャによって管理されるUIView階層にReact Nativeビューをポータルします。React NativeビューはUIViewとしてレンダリングされるため、これは実際には非常に簡単です。オーバーライドするだけです。

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex

そして、すべてのサブビューを新しいUIView階層にパイプします。#2については、<InputAccessoryView>に新しいRCTTouchHandlerを設定します。状態の更新は、通常のイベントコールバックを使用して実現されます。#3と#4については、<TextInput>コンポーネントの作成時に、ネイティブコードでアクセサリビューUIView階層を見つけるために、nativeIDフィールドを使用します。この関数は、基になるネイティブテキスト入力の.inputAccessoryViewプロパティを使用します。これにより、それらのObjC実装で<InputAccessoryView><TextInput>を効果的にリンクします。

スティッキーテキスト入力(シナリオ2)をサポートすると、さらにいくつかの制約が追加されます。この設計では、入力アクセサリビューには子としてテキスト入力があるため、nativeIDによるリンクはオプションではありません。代わりに、汎用的なオフスクリーンUIView.inputAccessoryViewをネイティブ<InputAccessoryView>階層に設定します。この汎用的なUIViewを手動でファーストレスポンダーにすることで、階層はレスポンダーインフラストラクチャによってマウントされます。この概念は、上記のブログ投稿で詳しく説明されています。

落とし穴

もちろん、このAPIの構築中、すべてが順風満帆だったわけではありません。遭遇した落とし穴をいくつか、そしてそれらをどのように修正したかを以下に示します。

このAPIを構築するための最初のアイデアは、NSNotificationCenterUIKeyboardWill(Show/Hide/ChangeFrame)イベントをリッスンすることでした。このパターンは、いくつかのオープンソースライブラリや、Facebookアプリの一部の内部で使用されています。残念ながら、UIKeyboardDidChangeFrameイベントは、スワイプ時に<InputAccessoryView>フレームを更新するのに十分なタイミングで呼び出されていませんでした。また、キーボードの高さが変化しても、これらのイベントではキャプチャされません。これにより、次のようなバグが発生します。

iPhone Xでは、テキストキーボードと絵文字キーボードの高さが異なります。キーボードイベントを使用してテキスト入力フレームを操作するほとんどのアプリケーションは、上記のバグを修正する必要がありました。私たちの解決策は、.inputAccessoryViewプロパティを使用することにコミットすることでした。つまり、レスポンダーインフラストラクチャがこのようにフレームの更新を処理します。


遭遇したもう一つの厄介なバグは、iPhone Xのホームインジケーター(ノッチ)を回避することでした。「Appleはまさにこの理由でsafeAreaLayoutGuideを開発したのだから、これは簡単だ!」と思うかもしれません。私たちも最初はそう思っていました。最初の問題は、ネイティブの<InputAccessoryView>実装には、表示される直前までアンカーとなるウィンドウがないことです。大丈夫、-(BOOL)becomeFirstResponderをオーバーライドして、そこでレイアウト制約を適用できます。これらの制約に従うことでアクセサリビューは上に移動しますが、別のバグが発生します。

入力アクセサリビューはホームインジケーターをうまく回避しますが、今度はセーフエリア外のコンテンツが表示されるようになります。解決策は、このradarにあります。ネイティブの<InputAccessoryView>階層を、safeAreaLayoutGuide制約に準拠しないコンテナでラップしました。ネイティブコンテナはセーフエリア外のコンテンツを覆い隠し、<InputAccessoryView>はセーフエリア内に留まります。


使用例

ここでは、<TextInput>の状態をリセットするキーボードツールバーボタンを作成する例を示します。

class TextInputAccessoryViewExample extends React.Component<
{},
*,
> {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text'};
}

render() {
const inputAccessoryViewID = 'inputAccessoryView1';
return (
<View>
<TextInput
style={styles.default}
inputAccessoryViewID={inputAccessoryViewID}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
<InputAccessoryView nativeID={inputAccessoryViewID}>
<View style={{backgroundColor: 'white'}}>
<Button
onPress={() =>
this.setState({text: 'Placeholder Text'})
}
title="Reset Text"
/>
</View>
</InputAccessoryView>
</View>
);
}
}

スティッキーテキスト入力の別の例は、リポジトリにあります

いつ使用できますか?

この機能実装の完全なコミットはこちらにあります。<InputAccessoryView>は、次のv0.55.0リリースで使用できるようになります。

快適なキーボード操作を! :)

React NativeでのAWSの使用

·9分間の読書
Richard Threlkeld
AWS Mobileシニアテクニカルプロダクトマネージャー

AWSは、テクノロジー業界でクラウドサービスプロバイダーとして広く知られています。これには、コンピューティング、ストレージ、データベーステクノロジーに加えて、完全に管理されたサーバーレスオファリングも含まれます。AWS Mobileチームは、顧客やJavaScriptエコシステムのメンバーと緊密に連携して、クラウド接続モバイルおよびWebアプリケーションのセキュリティ、スケーラビリティ、開発および展開の容易性を向上させてきました。完全なスターターキットから始めましたが、最近さらにいくつかの開発を行いました。

このブログ投稿では、ReactおよびReact Native開発者にとって興味深い点について説明します。

  • AWS Amplify、クラウドサービスを使用するJavaScriptアプリケーション向けの宣言型ライブラリ
  • AWS AppSync、オフラインとリアルタイム機能を備えた完全に管理されたGraphQLサービス

AWS Amplify

React Nativeアプリケーションは、Create React Native AppやExpoなどのツールを使用して非常に簡単にブートストラップできます。ただし、ユースケースをインフラストラクチャサービスに一致させようとすると、クラウドへの接続は困難になる場合があります。たとえば、React Nativeアプリで写真をアップロードする必要がある場合があります。これらはユーザーごとに保護する必要がありますか?おそらく、何らかの登録またはサインインプロセスが必要になります。独自のユーザーディレクトリを使用するか、ソーシャルメディアプロバイダーを使用しますか?おそらく、アプリはユーザーがログインした後、カスタムビジネスロジックを使用してAPIを呼び出す必要もあります。

これらの問題をJavaScript開発者が解決できるように、AWS Amplifyという名前のライブラリをリリースしました。設計は、AWS固有の実装ではなく、タスクの「カテゴリ」に分割されています。たとえば、ユーザーに登録、ログイン、プライベート写真のアップロードをさせたい場合は、AuthStorageのカテゴリをアプリケーションにプルインするだけです。

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));

Auth.confirmSignIn(user, code)
.then(data => console.log(data))
.catch(err => console.log(err));

上記のコードでは、Amplifyが支援する一般的なタスクの例(メールまたはSMSを使用した多要素認証(MFA)コードの使用など)を見ることができます。現在サポートされているカテゴリは次のとおりです。

  • Auth:資格情報の自動化を提供します。すぐに使用できる実装では、署名にAWS資格情報と、Amazon CognitoからのOIDC JWTトークンを使用します。MFA機能などの一般的な機能がサポートされています。
  • Analytics:1行のコードで、Amazon Pinpointで認証済みユーザーまたは未認証ユーザーのトラッキングを取得します。必要に応じて、カスタムメトリックまたは属性に拡張できます。
  • APIAWS署名バージョン4を利用して、安全な方法でRESTful APIと対話します。APIモジュールは、Amazon API Gatewayを使用したサーバーレスインフラストラクチャで優れています。
  • StorageAmazon S3でコンテンツをアップロード、ダウンロード、一覧表示するための簡素化されたコマンド。ユーザーごとにデータをパブリックコンテンツまたはプライベートコンテンツに簡単にグループ化することもできます。
  • Caching:実装固有の永続性を活用した、WebアプリとReact Native全体でのLRUキャッシュインターフェース。
  • i18nとロギング:国際化とローカリゼーション機能、およびデバッグとロギング機能を提供します。

Amplifyの良い点の1つは、特定のプログラミング環境の設計に「ベストプラクティス」をエンコードすることです。たとえば、顧客とReact Native開発者と協力して発見したことは、開発中に迅速に作業を完了させるために取ったショートカットが本番スタックにまで及ぶことです。これにより、スケーラビリティまたはセキュリティが損なわれ、インフラストラクチャの再設計とコードのリファクタリングを余儀なくされる可能性があります。

開発者がこれを回避するのに役立つ例として、AWS Lambdaを使用したサーバーレス参照アーキテクチャがあります。これらは、バックエンドの構築時にAmazon API GatewayとAWS Lambdaを連携して使用する際のベストプラクティスを示しています。このパターンは、AmplifyのAPIカテゴリにエンコードされています。このパターンを使用して、いくつかの異なるRESTエンドポイントと対話し、ヘッダーをLambda関数に渡してカスタムビジネスロジックを実行できます。これらの機能を使用して新しいReact Nativeプロジェクトまたは既存のプロジェクトをブートストラップするためのAWS Mobile CLIもリリースしました。開始するには、npmを介してインストールし、構成プロンプトに従ってください。

npm install --global awsmobile-cli
awsmobile configure

モバイルエコシステムに固有のエンコードされたベストプラクティスのもう1つの例は、パスワードセキュリティです。デフォルトのAuthカテゴリの実装は、ユーザー登録とサインインにAmazon Cognitoユーザープールを利用します。このサービスは、認証試行中にユーザーを保護する方法として、セキュアリモートパスワードプロトコルを実装しています。プロトコルの数学を読み進めてみたい場合は、原始根に対してパスワード検証者を計算する際に、大きな素数を使用する必要があることに気付くでしょう。グループを生成します。React Native環境では、JITが無効になっています。これにより、このようなセキュリティ操作のためのBigInteger計算のパフォーマンスが低下します。これを考慮して、プロジェクト内でリンクできるAndroidとiOSのネイティブブリッジをリリースしました。

npm install --save aws-amplify-react-native
react-native link amazon-cognito-identity-js

Expoチームがこれを最新のSDKに含めたことに興奮しています。これにより、イジェクトせずにAmplifyを使用できます。

最後に、React Native(およびReact)開発に固有のAmplifyには、サインアップとサインインなどの機能を簡単にラップするための高階コンポーネント(HOC)が含まれています。

import Amplify, { withAuthenticator } from 'aws-amplify-react-native';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

class App extends React.Component {
...
}

export default withAuthenticator(App);

基礎となるコンポーネントは<Authenticator />としても提供されており、UIを完全にカスタマイズできます。ユーザーの状態(サインイン済みかどうか、MFA確認を待っているかどうかなど)を管理するためのプロパティと、状態が変更されたときに実行できるコールバックも提供します。

同様に、さまざまなユースケースで使用できる一般的なReactコンポーネントがあります。これらを必要に応じてカスタマイズできます。たとえば、StorageモジュールでAmazon S3からすべてのプライベート画像を表示できます。

<S3Album
level="private"
path={path}
filter={(item) => /jpg/i.test(item.path)}/>

前述のように、プロップを使用して多くのコンポーネント機能を制御できます。パブリックまたはプライベートのストレージオプションもあります。ユーザーが特定のUIコンポーネントと対話するときに分析を自動的に収集する機能もあります。

return <S3Album track/>

AWS Amplifyは、グローバル初期化ルーチンまたはカテゴリレベルでの初期化を使用して、開発の規約優先設定スタイルを優先します。開始する最も簡単な方法は、aws-exportsファイルを使用することです。ただし、開発者は既存のリソースを使用してライブラリを個別に使用することもできます。

哲学を深く掘り下げて完全なデモを見るには、AWS re:Inventのビデオをご覧ください。

AWS AppSync

AWS Amplifyのリリース直後、AWS AppSyncもリリースしました。これは、オフラインとリアルタイムの両方の機能を備えた完全に管理されたGraphQLサービスです。ネイティブAndroidとiOSを含むさまざまなクライアントプログラミング言語でGraphQLを使用できますが、React Native開発者の中で非常に人気があります。これは、データモデルが単方向データフローとコンポーネント階層にうまく適合するためです。

AWS AppSyncを使用すると、独自のAWSアカウントのリソースに接続できます。つまり、データの所有権と制御を保持します。これはデータソースを使用して行われ、サービスはAmazon DynamoDBAmazon Elasticsearch、およびAWS Lambdaをサポートしています。これにより、スキーマとして単一のGraphQL APIで(NoSQLと全文検索などの)機能を組み合わせることができます。これにより、データソースを自由に組み合わせて使用できます。AppSyncサービスはスキーマからプロビジョニングすることもできます。そのため、AWSサービスに精通していない場合でも、GraphQL SDLを記述し、ボタンをクリックするだけで、自動的に実行を開始できます。

AWS AppSyncのリアルタイム機能は、よく知られたイベントベースのパターンを使用したGraphQLサブスクリプションを介して制御されます。AWS AppSyncのサブスクリプションは、GraphQLディレクティブを使用してスキーマで制御され、スキーマは任意のデータソースを使用できるため、Amazon DynamoDBおよびAmazon Elasticsearch Serviceを使用したデータベース操作から、またはAWS Lambdaを使用したインフラストラクチャの他の部分から通知をトリガーできます。

AWS Amplifyと同様に、AWS AppSyncを使用してGraphQL APIにエンタープライズセキュリティ機能を利用できます。このサービスでは、APIキーを使用して迅速に開始できます。ただし、本番環境に移行する際には、AWS Identity and Access Management (IAM)またはAmazon CognitoユーザープールのOIDCトークンを使用するように移行できます。タイプに対するポリシーを使用して、リゾルバーレベルでアクセスを制御できます。特定のデータベースリソースの所有者かどうかを検出するなど、実行時にきめ細かいアクセス制御チェックを行うための論理チェックを使用することもできます。リゾルバーの実行または個々のデータベースレコードへのアクセスに関するグループメンバーシップのチェックに関する機能もあります。

React Native開発者がこれらのテクノロジーについてさらに学習できるように、AWS AppSyncコンソールホームページで起動できる組み込みのGraphQLサンプルスキーマがあります。このサンプルは、GraphQLスキーマをデプロイし、データベーステーブルをプロビジョニングし、クエリ、ミューテーション、サブスクリプションを自動的に接続します。また、この組み込みスキーマ(およびReactの例)を活用したAWS AppSyncのReact Nativeの例もあり、クライアントコンポーネントとクラウドコンポーネントの両方を数分で実行できます。

AWSAppSyncClientを使用すると、Apollo Clientにプラグインされるため、簡単に開始できます。AWSAppSyncClientは、GraphQL APIのセキュリティと署名、オフライン機能、サブスクリプションのハンドシェイクとネゴシエーションプロセスを処理します。

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";

const client = new AWSAppSyncClient({
url: awsconfig.graphqlEndpoint,
region: awsconfig.region,
auth: {type: AUTH_TYPE.API_KEY, apiKey: awsconfig.apiKey}
});

AppSyncコンソールは、ダウンロード可能な設定ファイルを提供します。このファイルには、GraphQLエンドポイント、AWSリージョン、APIキーが含まれています。React Apolloを使用してクライアントを使用できます。

const WithProvider = () => (
<ApolloProvider client={client}>
<Rehydrated>
<App />
</Rehydrated>
</ApolloProvider>
);

この時点で、標準のGraphQLクエリを使用できます。

query ListEvents {
listEvents{
items{
__typename
id
name
where
when
description
comments{
__typename
items{
__typename
eventId
commentId
content
createdAt
}
nextToken
}
}
}
}

上記の例は、AppSyncによってプロビジョニングされたサンプルアプリスキーマを使用したクエリを示しています。DynamoDBとのインタラクションだけでなく、データのページネーション(暗号化されたトークンを含む)とEventsComments間のタイプの関係も含まれています。アプリはAWSAppSyncClientで構成されているため、データはオフラインで自動的に永続化され、デバイスが再接続されると同期されます。

この背後にあるクライアントテクノロジーとReact Nativeデモの詳細については、このビデオをご覧ください

フィードバック

ライブラリの背後にあるチームは、これらのライブラリとサービスがどのように機能するかを聞きたいと考えています。また、クラウドサービスを使用したReactとReact Nativeの開発をさらに容易にするために何ができるかを聞きたいと考えています。AWS AmplifyまたはAWS AppSyncについては、GitHubのAWS Mobileチームにお問い合わせください。

React NativeでTwitterのアプリ読み込みアニメーションを実装する

·11分間の読書
Eli White
Eli White
Metaのソフトウェアエンジニア

TwitterのiOSアプリには、私が非常に気に入っているローディングアニメーションがあります。

アプリの準備が整うと、Twitterのロゴが魅力的に展開し、アプリが表示されます。

このローディングアニメーションをReact Nativeで再現する方法を理解したいと思いました。


どのように構築するかを理解するために、まずローディングアニメーションの異なる部分を理解する必要がありました。微妙な点を理解する最も簡単な方法は、速度を落とすことです。

構築方法を理解する必要がある主要な部分がいくつかあります。

  1. 鳥のスケーリング。
  2. 鳥が大きくなるにつれて、下にあるアプリを表示する
  3. 最後にアプリを少し縮小する

このアニメーションを作成する方法は、かなり時間がかかりました。

私は、青い背景とTwitterの鳥がアプリのにレイヤーされており、鳥が大きくなるにつれて透明になり、下にあるアプリが表示されると言う誤った仮定から始めました。このアプローチは機能しません。なぜなら、Twitterの鳥が透明になると、アプリではなく青いレイヤーが表示されるためです。

幸いなことに、親愛なる読者の皆さん、私は同じ苦労をする必要はありません。この素晴らしいチュートリアルでは、良い部分にスキップできます。


正しい方法

コードに移る前に、これをどのように分解するかを理解することが重要です。この効果を視覚化するために、CodePen(いくつかの段落に埋め込まれています)で再現しました。そのため、インタラクティブに異なるレイヤーを確認できます。

この効果には、主に3つのレイヤーがあります。1つ目は青い背景レイヤーです。これはアプリの上に表示されているように見えますが、実際には後ろにあります。

次に、プレーンな白いレイヤーがあります。そして最後に、最前面にはアプリがあります。


このアニメーションの主なトリックは、Twitterのロゴをmaskとして使用し、アプリと白いレイヤーの両方をマスクすることです。マスキングの詳細については詳しく説明しません。それについては、豊富なリソースがオンラインにあります

このコンテキストでのマスキングの基本は、マスクの不透明なピクセルがマスクしているコンテンツを表示し、マスクの透明なピクセルがマスクしているコンテンツを隠す画像を持つことです。

Twitterのロゴをマスクとして使用し、ソリッドホワイトレイヤーとアプリレイヤーの2つのレイヤーをマスクします。

アプリを表示するには、マスクを画面全体よりも大きくなるまで拡大します。

マスクが拡大している間、アプリレイヤーの不透明度をフェードインして、アプリを表示し、その背後にあるソリッドホワイトレイヤーを隠します。効果を完成させるには、アプリレイヤーをスケール>1で開始し、アニメーションの終了時に1まで縮小します。その後、非アプリレイヤーは表示されなくなるため、非表示にします。

絵は千言万語に値すると言われています。インタラクティブな視覚化は、何語に相当するのでしょうか?「次のステップ」ボタンをクリックしてアニメーションをクリックしてください。レイヤーを表示すると、側面からの視点が表示されます。グリッドは、透明なレイヤーを視覚化するのに役立ちます。

さあ、React Nativeへ

了解しました。構築する内容とアニメーションの動作がわかったので、コードに進むことができます。これは、あなたが本当にここにいる理由です。

このパズルの主要な部分は、コアReact NativeコンポーネントであるMaskedViewIOSです。

import {MaskedViewIOS} from 'react-native';

<MaskedViewIOS maskElement={<Text>Basic Mask</Text>}>
<View style={{backgroundColor: 'blue'}} />
</MaskedViewIOS>;

MaskedViewIOSは、プロップmaskElementchildrenを受け取ります。子要素はmaskElementによってマスクされます。マスクは画像である必要はなく、任意のビューにすることができることに注意してください。上記の例では、青いビューがレンダリングされますが、これはmaskElementから「Basic Mask」という単語がある場合にのみ表示されます。複雑な青いテキストを作成しただけです。

やりたいことは、青いレイヤーをレンダリングし、その上にTwitterのロゴを使用してマスクされたアプリと白いレイヤーをレンダリングすることです。

{
fullScreenBlueLayer;
}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Image source={twitterLogo} />
</View>
}>
{fullScreenWhiteLayer}
<View style={{flex: 1}}>
<MyApp />
</View>
</MaskedViewIOS>;

これにより、以下に示すレイヤーが得られます。

アニメーションの部分へ

機能させるために必要な部品がすべて揃ったので、次のステップはそれらをアニメーション化することです。このアニメーションをスムーズにするために、React NativeのAnimated APIを利用します。

Animatedを使用すると、JavaScriptでアニメーションを宣言的に定義できます。デフォルトでは、これらのアニメーションはJavaScriptで実行され、ネイティブ層に各フレームで行う変更を指示します。JavaScriptは毎フレームアニメーションを更新しようとしますが、おそらく十分な速度で更新できず、フレームのドロップ(ジャンク)が発生します。これは望ましいことではありません。

Animatedには、このジャンクなしでアニメーションを取得できるようにする特別な動作があります。Animatedには、アニメーションの開始時にJavaScriptからネイティブにアニメーション定義を送信するuseNativeDriverというフラグがあり、ネイティブ側が毎フレームJavaScriptとのやり取りを行うことなくアニメーションの更新を処理できるようにします。useNativeDriverの欠点は、主にtransformopacityなどの特定のプロパティのみを更新できることです。少なくとも今のところ、useNativeDriverで背景色のようなものをアニメーション化することはできません。今後追加していく予定ですし、もちろん、プロジェクトに必要なプロパティのPRを送信することもできます。コミュニティ全体に利益をもたらします😀。

このアニメーションをスムーズにしたいので、これらの制約内で作業します。useNativeDriverが内部でどのように機能するかを詳しく知りたい場合は、発表されたブログ記事をご覧ください。

アニメーションの分解

アニメーションには4つのコンポーネントがあります。

  1. 鳥を拡大して、アプリとソリッドホワイトレイヤーを表示する
  2. アプリをフェードインする
  3. アプリを縮小する
  4. 完了したら、白いレイヤーと青いレイヤーを非表示にする

Animatedには、アニメーションを定義する2つの主要な方法があります。1つ目はAnimated.timingを使用する方法で、アニメーションの実行時間を正確に指定し、イージングカーブを使用して動きをスムーズにします。もう1つの方法は、Animated.springなどの物理ベースのAPIを使用する方法です。Animated.springを使用すると、バネの摩擦量や張力などのパラメーターを指定し、物理でアニメーションを実行できます。

同時に実行したい、互いに密接に関連した複数のアニメーションがあります。たとえば、アプリのフェードイン開始と同時に、マスクが途中で表示されるようにしたいと考えています。これらのアニメーションは密接に関連しているため、単一のAnimated.Valueを使用してAnimated.timingを使用します。

Animated.Valueは、ネイティブ値をラップしたもので、Animatedはこれを使用してアニメーションの状態を認識します。通常、完全なアニメーションに対しては、これらを1つだけ持つことをお勧めします。Animatedを使用するほとんどのコンポーネントは、状態に値を格納します。

このアニメーションを、完全なアニメーションの異なる時点で行われるステップとして考えているため、Animated.Valueを0(完了率0%)から開始し、100(完了率100%)で終了します。

初期コンポーネントの状態は次のようになります。

state = {
loadingProgress: new Animated.Value(0),
};

アニメーションを開始する準備ができたら、Animatedにこの値を100にアニメーション化するように指示します。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true, // This is important!
}).start();

次に、アニメーションのさまざまな部分と、全体アニメーションのさまざまな段階でそれらが持つべき値のおおよその見積もりを計算しようとします。以下は、アニメーションのさまざまな部分と、時間が経過するにつれて異なる時点でそれらの値がどうなるかについての表です。

Twitterのバードマスクはスケール1から始まり、上に飛び上がる前に小さくなります。したがって、アニメーションの10%で、スケール値が0.8になり、最後にスケール70まで上昇する必要があります。正直言って、70を選択するのはかなり恣意的でした。バードが画面全体を完全に表示するのに十分な大きさにする必要があり、60では不十分でした😀。ただし、この部分の興味深い点は、数字が大きいほど、同じ時間でそこに到達する必要があるため、成長しているように見える速度が速くなることです。この数値は、このロゴでうまく見えるようにするために、試行錯誤を重ねて得られました。サイズが異なるロゴ/デバイスでは、画面全体が表示されるように、この最終スケールを調整する必要があります。

アプリはしばらく不透明なままにしておく必要があります。少なくともTwitterのロゴが小さくなるまでは。公式のアニメーションに基づいて、バードがスケールアップの途中で表示され始め、非常に迅速に完全に表示されるようにしたいと考えています。したがって、15%で表示を開始し、全体アニメーションの30%で完全に表示されます。

アプリのスケールは1.1から始まり、アニメーションの終わりまでに通常のスケールまで縮小します。

そして今、コードで。

基本的に上記で行ったのは、アニメーションの進行状況の割合から個々の部分の値へのマッピングです。.interpolateを使用してAnimatedでそれを行います。アニメーションの各部分に対して3つの異なるスタイルオブジェクトを作成し、this.state.loadingProgressに基づいた補間された値を使用します。

const loadingProgress = this.state.loadingProgress;

const opacityClearToVisible = {
opacity: loadingProgress.interpolate({
inputRange: [0, 15, 30],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
// clamp means when the input is 30-100, output should stay at 1
}),
};

const imageScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 10, 100],
outputRange: [1, 0.8, 70],
}),
},
],
};

const appScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 100],
outputRange: [1.1, 1],
}),
},
],
};

これらのスタイルオブジェクトが作成されたので、投稿の前のビューのスニペットをレンダリングする際に使用できます。Animated.Valueを使用するスタイルオブジェクトは、Animated.ViewAnimated.TextAnimated.Imageのみが使用できることに注意してください。

const fullScreenBlueLayer = (
<View style={styles.fullScreenBlueLayer} />
);
const fullScreenWhiteLayer = (
<View style={styles.fullScreenWhiteLayer} />
);

return (
<View style={styles.fullScreen}>
{fullScreenBlueLayer}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Animated.Image
style={[styles.maskImageStyle, imageScale]}
source={twitterLogo}
/>
</View>
}>
{fullScreenWhiteLayer}
<Animated.View
style={[opacityClearToVisible, appScale, {flex: 1}]}>
{this.props.children}
</Animated.View>
</MaskedViewIOS>
</View>
);

やった!アニメーションの部分が期待どおりに見えます。あとは、二度と表示されない青と白のレイヤーを整理するだけです。

それらを整理できるかどうかを知るには、アニメーションが完了した時点を知る必要があります。幸いにも、Animated.timingを呼び出す場所では、.startは、アニメーションが完了したときに実行されるオプションのコールバックを受け取ります。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true,
}).start(() => {
this.setState({
animationDone: true,
});
});

これで、アニメーションが完了したかどうかを知るための値がstateにあるので、青と白のレイヤーを修正してそれを使用できます。

const fullScreenBlueLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenBlueLayer]} />
);
const fullScreenWhiteLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenWhiteLayer]} />
);

さあ!アニメーションが機能するようになり、アニメーションが完了したら使用されていないレイヤーをクリーンアップします。Twitterアプリの読み込みアニメーションを作成しました!

しかし、私のものは機能しません!

心配しないでください、読者の皆さん。私も、コードの一部しか提供せず、完成したソースを提供しないガイドが嫌いです。

このコンポーネントはnpmに公開されており、react-native-mask-loaderとしてGitHubにあります。これを携帯電話で試すには、Expoでここにあります

さらに読む/追加課題

  1. このgitbookは、React Nativeのドキュメントを読んだ後に、Animatedについてさらに学ぶための優れたリソースです。
  2. 実際のTwitterアニメーションは、マスクの表示を終了時に高速化しているようです。その動作に最適に一致するように、ローダーを別のイージング関数(またはスプリング!)を使用するように変更してみてください。
  3. マスクの現在の最終スケールはハードコードされており、タブレットではアプリ全体が表示されない可能性があります。画面サイズと画像サイズに基づいて最終スケールを計算することは、素晴らしいPRになるでしょう。

React Native Monthly #6

·読了時間:4分
Tomislav Tenodi
Speckの創設者

React Nativeの月例会議は依然として盛況です!この投稿の一番下にあるメモで次回のセッションを確認してください。

Expo

  • 「Full Stack React Native」本のプレリリースおめでとうございます、Devin Abbottさん、Houssein Djirdehさん!これは、いくつかの小さなアプリを構築することでReact Nativeの学習方法を案内します。書籍を購入する前に、https://www.fullstackreact.com/react-native/でこれらのアプリを試すことができます。
  • reason-react-native-scriptsの最初の(実験的な)バージョンをリリースして、人々がReasonMLを簡単に試せるようにしました。
  • Expo SDK 24がリリースされました!これはReact Native 0.51を使用しており、多くの新機能と改善が含まれています。スタンドアロンアプリでの画像のバンドル(最初の読み込み時にキャッシュする必要はありません!)、画像操作API(トリミング、サイズ変更、回転、反転)、顔検出API、新しいリリースチャネル機能(特定のチャネルのアクティブなリリースの設定とロールバック)、スタンドアロンアプリのビルドを追跡するためのWebダッシュボード、そしてAndroidマルチタスクとOpenGL Android実装の長期的なバグ修正など、ほんの一例です。
  • 1月よりReact Navigationにリソースを投入しています。ReactコンポーネントとAnimatedやreact-native-gesture-handlerのようなプリミティブだけでReact Nativeのナビゲーションを構築することが可能であり、望ましいと強く信じており、計画しているいくつかの改善に非常に興奮しています。コミュニティに貢献したいと考えている場合は、react-native-mapsreact-native-svgをチェックしてください。どちらも助けが必要です!

Infinite Red

Microsoft

  • コアReact Native Windowsブリッジを.NET Standardに移行するためのプルリクエストが開始されました。これにより、事実上OSに依存しなくなります。多くの他の.NET Coreプラットフォームが、独自のthreadingモデル、JavaScriptランタイム、およびUIManagers(JavaScriptCore、Xamarin.Mac、Linux Gtk#、Samsung Tizenオプションなどを考えてください)でブリッジを拡張できることを期待しています。

Wix

  • Detox
    • E2Eテストでスケールアップするために、CIに費やす時間を最小限に抑えたいと考えており、Detoxのパラレル処理サポートに取り組んでいます。
    • E2Eでのモックをより適切にサポートするために、カスタムフレーバービルドのサポートを有効にするためのプルリクエストを提出しました。
  • DetoxInstruments
    • DetoxInstrumentsのキラー機能の開発は非常に困難な作業であることが証明されています。いつでもJavaScriptのバックトレースを取得するには、JSスレッドの一時停止をサポートするカスタムJSCore実装が必要です。Wixのアプリで内部的にプロファイラーをテストしたところ、JSスレッドに関する興味深い洞察が得られました。
    • このプロジェクトはまだ一般的に使用できるほど安定していませんが、積極的に取り組んでおり、近いうちに発表できることを願っています。
  • React Native Navigation
    • V2の開発ペースが大幅に向上しました。これまで、1人の開発者が時間の20%を費やして作業していましたが、現在は3人の開発者がフルタイムで作業しています!
  • Androidのパフォーマンス
    • RNにバンドルされた古いJSCoreを最新のバージョン(カスタムJIT構成を使用したwebkitGTKプロジェクトの先端)に置き換えたところ、JSスレッドのパフォーマンスが40%向上しました。次に、その64ビットバージョンをコンパイルします。この取り組みは、AndroidのJSCビルドスクリプトに基づいています。現在の状況はこちらで確認してください。

次回のセッション

この会議の目的を、単一の特定のトピック(例:ナビゲーション、React Nativeモジュールの別のリポジトリへの移動、ドキュメントなど)を議論することに変更することについて議論がありました。そうすることで、React Nativeコミュニティに最高の貢献ができると思います。次回の会議で実施される可能性があります。どのようなトピックを取り上げてほしいか、ツイートしてください。

React Native Monthly #5

·読了時間:4分
Tomislav Tenodi
Speckの創設者

React Nativeの月例会議が継続します!私たちのチームが取り組んでいることを見てみましょう。

Callstack

  • React Native CIに取り組んできました。最も重要なのは、TravisからCircleに移行し、React Nativeに単一の統合されたCIパイプラインを残したことでしょう。
  • 私たちは、参加者と共に多くのオープンソースプロジェクトにプルリクエストを送信しようと試みたHacktoberfest - React Native版を開催しました。
  • 私たちはHaulの開発を継続しています。先月は、webpack 3のサポートを含む2つの新しいリリースを発表しました。CRNAExpoのサポートを追加し、より良いHMRに取り組む予定です。ロードマップは問題トラッカーで公開されています。改善点の提案やフィードバックがありましたら、お知らせください!

Expo

  • Expo SDK 22(React Native 0.49を使用)をリリースし、それに合わせてCRNAを更新しました。
    • 改善されたスプラッシュスクリーンAPI、基本的なARKitサポート、「DeviceMotion」API、iOS11でのSFAuthenticationSessionサポート、そしてその他が含まれています。
  • あなたのSnackは、複数のJavaScriptファイルを持つことができるようになり、エディターにドラッグアンドドロップするだけで画像やその他のアセットをアップロードできるようになりました。
  • iPhone Xのサポートを追加するためにreact-navigationに貢献してください。
  • Expoを使用した大規模アプリケーション構築における課題に焦点を当てています。例えば
    • ステージング、本番、および任意のチャネルへの複数環境への展開に対するファーストクラスのサポート。チャネルは、ロールバックと特定チャネルのアクティブなリリースの設定をサポートします。早期テスターにご参加いただける方は@expo_ioまでお知らせください。
    • スタンドアロンアプリのビルドインフラストラクチャの改善と、スタンドアロンアプリビルドにおける画像やその他の非コードアセットのバンドルサポートの追加に取り組んでおり、同時にOTA(Over The Air)でのアセット更新機能も維持します。

Facebook

  • RTLサポートの改善
    • 方向を認識するスタイルをいくつか導入しています。
      • 位置
        • (left|right) → (start|end)
      • マージン
        • margin(Left|Right) → margin(Start|End)
      • パディング
        • padding(Left|Right) → padding(Start|End)
      • ボーダー
        • borderTop(Left|Right)Radius → borderTop(Start|End)Radius
        • borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
        • border(Left|Right)Width → border(Start|End)Width
        • border(Left|Right)Color → border(Start|End)Color
    • 位置、マージン、パディング、ボーダーのスタイルでは、RTLにおいて「left」と「right」の意味が入れ替わっていました。数ヶ月以内にこの動作を削除し、「left」は常に「left」、「right」は常に「right」を意味するように変更します。破壊的変更はフラグで隠されています。React Nativeコンポーネントで`I18nManager.swapLeftAndRightInRTL(false)`を使用すると、これらの変更を適用できます。
  • 内部ネイティブモジュールのFlow型付けと、それらを使用してJavaのインターフェースとObjCのプロトコルを生成し、ネイティブ実装が実装する必要があります。このコード生成は、早ければ来年、オープンソースになることを期待しています。

Infinite Red

  • React Nativeおよびその他のプロジェクトを支援するための新しいOSSツール。詳細はこちら
  • 新しいボイラープレートリリース(コード名:Bowser)に向けてIgniteを刷新しています。

Shoutem

  • Shoutemでの開発フローを改善しています。アプリの作成から最初のカスタム画面の作成までのプロセスを合理化し、非常に簡単にしたいと考えています。これにより、React Native開発者にとっての障壁が低くなります。新しい機能を試すためにいくつかのワークショップを用意しました。Shoutem CLIも新しいフローをサポートするように改善しました。
  • Shoutem UIは、いくつかのコンポーネントの改善とバグ修正が行われました。最新のReact Nativeバージョンとの互換性も確認しました。
  • Shoutemプラットフォームはいくつかの注目すべきアップデートを受け、新しい統合はオープンソースの拡張プロジェクトの一部として利用可能です。他の開発者によるShoutem拡張の活発な開発を見て、私たちは本当に興奮しています。私たちは積極的に連絡を取り、彼らの拡張についてアドバイスとガイダンスを提供しています。

次回のセッション

次回のセッションは、2017年12月6日(水曜日)に予定されています。会議の成果をどのように改善すべきかについてご提案がありましたら、Twitterで私にご連絡ください。

React Native Monthly #4

読了時間3分
Mike Grabowski
マイク・グラボウスキー
CallstackのCTO兼共同創設者

React Native月例会議が継続中です!各チームからのメモをご紹介します。

Callstack

  • React Native EUが終了しました。33カ国から300名以上の参加者がヴロツワフを訪れました。講演内容はYouTubeでご覧いただけます。
  • カンファレンスの後、徐々にオープンソースのスケジュールに戻っています。特筆すべき点として、既存の問題の大部分を修正するreact-native-opentokの次期リリースに取り組んでいることが挙げられます。

GeekyAnts

React Nativeを採用する開発者にとっての参入障壁を、以下の点で下げようとしています。

  • React Native EUBuilderX.ioを発表しました。BuilderXは、JavaScriptファイル(現時点ではReact Nativeのみサポート)と直接連携して、美しく、可読性が高く、編集可能なコードを生成するデザインツールです。
  • 次のReact Nativeプロジェクトのためのボイラープレートのセットを提供するReactNativeSeed.comを立ち上げました。データ型にはTypeScriptとFlow、状態管理にはMobX、Redux、mobx-state-treeを使用し、スタックにはCRNAとプレーンなReact-Nativeを含むさまざまなオプションがあります。

Expo

  • まもなくSDK 21をリリースします。これには、react-native 0.48.3のサポートと、Expo SDKのバグ修正/信頼性の向上/新機能(ビデオ録画、新しいスプラッシュスクリーンAPI、`react-native-gesture-handler`のサポート、エラー処理の改善など)が含まれています。
  • react-native-gesture-handlerに関しては、Krzysztof MagieraSoftware Mansion)が開発を推進しており、私たちはテストと開発時間の資金援助を行っています。SDK 21でExpoに統合することで、Snackで簡単に試せるようになるため、人々がどのような成果を生み出すか楽しみです。
  • エラーログ/処理の改善については、ログに関する詳細(特に「問題2」)はExpoの内部PRに関するこのgist、npm標準ライブラリモジュールのインポート失敗を処理する変更についてはこのコミットを参照してください。React Nativeの上流でエラーメッセージをこのように改善する機会はたくさんあり、私たちは上流のPRをフォローアップしていきます。コミュニティの皆さんも参加していただけると嬉しいです。
  • native.directoryは成長を続けており、GitHubのリポジトリからプロジェクトを追加できます。
  • PennAppsHack The NorthHackMITなど、北米で開催されるハッカソンに参加しています。まもなくMHacksにも参加します。

Facebook

  • Androidの<Text>コンポーネントと<TextInput>コンポーネントの改善に取り組んでいます。(<TextInput>のネイティブ自動拡張;入れ子になった<Text>コンポーネントのレイアウト問題;より良いコード構造;パフォーマンス最適化)
  • 問題とプルリクエストのトリアージを手伝っていただける貢献者を募集しています。

Microsoft

  • CodePushのコード署名機能をリリースしました。React Native開発者は、CodePushでアプリケーションバンドルに署名できるようになりました。発表はこちら
  • CodePushとMobile Centerの統合を完了することに取り組んでいます。テスト/クラッシュ統合も検討しています。

次回のセッション

次回のセッションは、2017年10月10日(水曜日)に予定されています。これは4回目の会議に過ぎないため、これらのメモがReact Nativeコミュニティにどのように役立つかを知りたいと思っています。会議の成果をどのように改善すべきかについてご提案がありましたら、Twitterで私にご連絡ください。

React Native Monthly #3

読み時間5分
Mike Grabowski
マイク・グラボウスキー
CallstackのCTO兼共同創設者

React Native月例会議が継続中です!今月の会議は、ほとんどのチームがリリースに忙しかったため、少し短くなりました。来月は、ポーランドのヴロツワフで開催されるReact Native EUカンファレンスに参加します。チケットを確保して、現地でお会いしましょう!一方、各チームの取り組みを見ていきましょう。

チーム

3回目の会議では、5つのチームが参加しました。

メモ

各チームからのメモをご紹介します。

Callstack

  • 最近、react-native-material-paletteをオープンソース化しました。これは、画像から主要な色を抽出し、視覚的に魅力的なアプリを作成するのに役立ちます。現時点ではAndroidのみですが、将来的にはiOSのサポートを追加することを検討しています。
  • haulにHMRサポートとその他多くの優れた機能を追加しました!最新のリリースをご覧ください。
  • React Native EU 2017が開催されます!来月はReact Nativeとポーランド一色です!残りのチケットをこちらで入手してください。

Expo

  • Snackでnpmパッケージのインストールをサポートしました。通常のExpoの制限が適用されます—パッケージは、Expoに既に含まれていないカスタムネイティブAPIに依存することはできません。複数ファイルのサポートとSnackへのアセットのアップロードにも取り組んでいます。SatyajitReact Native EuropeでSnackについて講演します。
  • カメラ、決済機能、セキュアストレージ、磁力計、ファイルダウンロードの一時停止/再開機能、および改善されたスプラッシュ/ローディング画面を搭載したSDK20をリリースしました。
  • Krzysztof と共に react-native-gesture-handler の開発を継続しています。ぜひお試しいただき、PanResponderまたはネイティブジェスチャー認識機能を使用して以前作成したジェスチャーを再構築し、発生した問題点をお知らせください。
  • JSCデバッグプロトコルを試行しており、Canny での多数の機能リクエストに取り組んでいます。

Facebook

  • 先月、GitHubのイシュートラッカーの管理について議論し、プロジェクトの保守性を向上させるための改善を試みることに合意しました。
  • 現在、未解決のイシュー数は約600件で推移しており、しばらくこの状態が続く可能性があります。過去1ヶ月で、アクティビティがない(過去60日間コメントがない)ことを理由に690件のイシューをクローズしました。その690件のうち、様々な理由で58件が再オープンされました(メンテナが修正を行うことを約束した場合、またはコントリビュータがイシューをオープン状態に維持する正当な理由を示した場合など)。
  • 当面の間、古いイシューの自動クローズを継続する予定です。トラッカーに登録されたすべての影響のあるイシューに対応できる状態を目指していますが、まだその段階には達していません。メンテナの皆様には、イシューのトリアージを行い、特に新規プロジェクトに影響を与える回帰や破壊的変更を招くイシューを見逃さないようにするため、可能な限りのご協力をお願いいたします。お手伝いいただける方は、Facebook GitHub Botを使用してイシューとプルリクエストのトリアージを行うことができます。新しいメンテナガイドには、トリアージとGitHub Botの使用方法に関する詳細情報が記載されています。イシュータスクフォース にご登録いただき、他のアクティブなコミュニティメンバーにもご参加を促してください!

Microsoft

  • 新しいSkypeアプリは、プラットフォーム間のコード共有を最大限に容易にするためにReact Nativeを基盤として構築されています。React NativeベースのSkypeアプリは現在、AndroidとiOSのアプリストアで利用可能です。
  • SkypeアプリをReact Nativeで構築する際に、バグや不足している機能に対処するためにReact Nativeにプルリクエストを送信しています。これまでに、約70件のプルリクエストがマージされました。
  • React Nativeにより、AndroidとiOSの両方のSkypeアプリを同じコードベースから提供することができました。また、そのコードベースを使用してSkypeウェブアプリも提供したいと考えています。この目標を達成するために、React/React Native上に構築された薄いレイヤーであるReactXPを構築し、オープンソース化しました。ReactXPは、クロスプラットフォームコンポーネントのセットを提供し、iOS/Androidをターゲットとする場合はReact Nativeに、Webをターゲットとする場合はreact-domにマッピングされます。ReactXPの目標は、React Native for Webと呼ばれる別のオープンソースライブラリと似ています。これらのライブラリの方法の違いについては、ReactXPのFAQに簡単に説明されています。

Shoutem

  • Shoutem を使用したアプリ開発時の開発者エクスペリエンスの改善と簡素化に向けた取り組みを継続しています。
  • すべてのアプリをreact-navigationに移行し始めましたが、より安定したバージョンがリリースされるまで、またはネイティブナビゲーションソリューションのいずれかが安定するまで延期しました。
  • すべてのエクステンションと、ほとんどのオープンソースライブラリ(animationthemeui)をReact Native 0.47.1にアップデートしました。

次回のセッション

次回のセッションは、2017年9月13日(水曜日)に予定されています。これは3回目のミーティングに過ぎませんが、これらのノートがReact Nativeコミュニティにどのように役立つかを知りたいと考えています。ミーティングの成果をどのように改善すべきかについてご提案がありましたら、Twitterで気軽にご連絡ください。