React Nativeへのコールドダイブ(初心者向けチュートリアル)

公開: 2022-03-11

React Nativeが発表されたとき、最初の反応は圧倒的にポジティブでした。 従来、モバイル空間のWebテクノロジーについて考えるとき、Apache Cordovaのようなものが思い浮かびます。これにより、WebサイトまたはWebアプリケーションをモバイルプラットフォーム用のアプリケーションとしてパッケージ化できます。 この初心者向けチュートリアルでは、React Nativeのアーキテクチャー、React Nativeの背後にある哲学、および同じスペース内の他のソリューションとの違いについて説明します。 記事の終わりまでに、Reactの「HelloWorld」アプリケーションをReactNativeアプリケーションに変換します。

まず、ReactNativeは比較的新しいテクノロジーであると言いましょう。 2015年3月から正式に利用可能になり、その年の初めからプライベートベータ版であり、その前にしばらくの間Facebookで内部的に使用されていました。 「ローマは一日にして成らず」ということわざは、一般的にテクノロジーにも当てはまります。 gruntのようなツールやNode.jsのようなプラットフォームは、成熟するまでに何年もかかりました。 Webの世界では、物事は急速に進んでおり、膨大な数のフレームワーク、パッケージ、ツールが毎日登場しているため、開発者はもう少し懐疑的になり、すべての誇大宣伝に飛びつきたくない傾向があります。彼らはベンダーロックインの状況に陥りました。 React Nativeを特別なものにしている理由、それが参加する価値のあるテクノロジーである理由を説明し、すべてがユニコーンやレインボーではないいくつかの例を取り上げます。

フードの下

モバイルでのWebテクノロジーについて話す場合、利用可能なソリューションは通常、次のいずれかのカテゴリに分類されます。

モバイルWebブラウザでのWebアプリケーションのバンドル

Webアプリケーションは、通常WebViewと呼ばれるモバイルブラウザに存在します。 大きなリファクタリングがなくても、WebサイトまたはWebアプリケーションはモバイルデバイスで動作します。 完全なユーザーエクスペリエンスを実現するには、デバイスの向きの変更をタップしたり聞いたりするなどのモバイルブラウザイベントや小さな画面を考慮する必要があるかもしれませんが、最小限の労力で動作するモバイルバージョンがあります。 Cordova / PhoneGapは、このカテゴリで最も人気のあるオプションです。 残念ながら、このオプションには大きな欠点があります。場合によっては、Cordovaを使用して開発されたアプリケーションは、特にグラフィックが多いアプリケーションの場合、ネイティブアプリケーションよりも大幅に遅くなります。 その他の場合、モバイルオペレーティングシステムは、モバイルブラウザで利用できるWebViewのすべての機能を実際に提供しているわけではありません。 ユーザーエクスペリエンスもネイティブアプリケーションとは異なる場合があります。 これは、アプリケーションまたはプラットフォーム自体が原因で発生する可能性があります。 この問題は、スクロールバーが同じように感じられないことから、要素をタップするときに目立った遅延が発生することまでさまざまです。

ネイティブテクノロジーへのコンパイル

まったく異なる解決策は、最終的にネイティブコードベースを作成することです。 これは、元のソースコードを別のプログラミング言語に変換することで発生します。 ネイティブパフォーマンスを、いくつかの不確実性を伴う抽象化レイヤーと交換します。 クローズドソースソリューションの場合、内部で何が起こっているのか、どのようなブラックボックスを扱っているのかさえわかりません。 その他の場合、次のモバイルオペレーティングシステムの更新によってコードがどの程度破損するか、修正または更新がいつ利用可能になるかがわかりません。 このカテゴリの人気のある例はHaxeです。

JavaScriptレイヤーの使用

ここでは、モバイル環境のJavaScriptエンジンを使用し、そこでJavaScriptを実行します。 ネイティブコントロールはJavaScriptオブジェクトと関数にマップされているため、 fancyButtonRightHere()という関数を呼び出すと、画面にボタンが表示されます。 NativeScriptまたはAppceleratorTitaniumは、このカテゴリのよく知られた例です。

React Nativeは、3番目のカテゴリーからのものとして分類できます。 iOSおよびAndroidバージョンの場合、React Nativeは内部でJavaScriptCoreを使用します。これは、iOSのデフォルトのJavaScriptエンジンです。 JavaScriptCoreは、AppleのSafariブラウザのJavaScriptエンジンでもあります。 OS XおよびiOSの開発者は、必要に応じて実際に直接インターフェースをとることができます。

大きな違いの1つは、React NativeがJavaScriptコードを別のスレッドで実行するため、ユーザーインターフェイスがブロックされず、アニメーションが滑らかでスムーズになることです。

Reactが重要な機能です

ReactNativeの「React」が誤ってそこに置かれていないことは注目に値します。 React Nativeの場合、Reactが提供するものを正確に理解する必要があります。 以下の概念は、ReactとReact Nativeの両方で同じように機能しますが、これらのコード例はブラウザーで実行するように調整されています。

シングルレンダリングエントリポイント

単純なReactコンポーネントを見ると、最初に気付くのは、コンポーネントにrender機能があることです。 実際、コンポーネント内にレンダリング関数が定義されていない場合、Reactはエラーをスローします。

 var MyComponent = function() { this.render = function() { // Render something here }; };

特別なことは、ここではDOM要素をいじらないことですが、DOMでレンダリングされるものを表すXMLベースの構造を返します。 このXMLベースの構成はJSXと呼ばれます。

 var MyComponent = function() { this.render = function() { return <div className="my-component">Hello there</div>; }; };

特別なJSXトランスフォーマーは、そのXMLに見えるコードをすべて受け取り、それを関数に変換します。 変換後のコンポーネントは次のようになります。

 var MyComponent = function() { this.render = function() { return React.createElement("div", { className: "my-component" }, "Hello there"); }; };

最大の利点は、コンポーネントをざっと見ることで、コンポーネントが何をするのかを常に把握できることです。 たとえば、 <FriendList />コンポーネントは、いくつかの<Friend />コンポーネントをレンダリングする場合があります。 render関数内以外の場所でコンポーネントをレンダリングすることはできないため、レンダリングされたコンポーネントがどこから来たのか正確にわからないという心配はありません。

一方向のデータフロー

コンポーネントのコンテンツを構築するために、Reactはプロパティまたは小道具を略して提供します。 XML属性と同様に、小道具をコンポーネントに直接渡し、構築されたコンポーネント内で小道具を使用できます。

 var Hello = function(props) { this.render = function() { return <div className="my-component">Hello {props.name}</div>; }; }; var Greeter = function() { this.render = function() { return <Hello name="there" /> } };

これにより、コンポーネントがツリーのような構造になり、子要素を作成するときにのみデータを渡すことができます。

変更時に再レンダリング

小道具に加えて、コンポーネントは内部状態を持つこともできます。 その動作の最も顕著な例は、ボタンが押されたときにその値を更新するクリックカウンターです。 クリック数自体が状態に保存されます。

小道具と状態の変化のそれぞれが、コンポーネントの完全な再レンダリングをトリガーします。

仮想DOM

小道具や状態が変化したときにすべてが再レンダリングされると、どうしてReact自体がそれをうまく実行しているのでしょうか。 魔法の要素は「仮想DOM」です。 何かを再レンダリングする必要があるときはいつでも、更新されたDOMの仮想表現が生成されます。 仮想DOMは、コンポーネントツリーをモデルにした要素の軽い表現で構成されているため、実際のDOM要素を生成するよりもはるかに効率的に要素を生成できます。 変更を実際のDOMに適用する前に、コンポーネントツリーのどこで変更が発生したかを正確に判断するためのチェックが行われ、差分が作成され、それらの特定の変更のみが適用されます。

このReactNativeチュートリアルの開始

初心者がReactNative用に開発するために設定する必要がある特定の前提条件があります。 iOSがサポートされた最初のプラットフォームであり、このチュートリアルで取り上げているプラ​​ットフォームであるため、少なくともバージョン6.3のmacOSとXcodeが必要です。 Node.jsも必要です。 役立つのは、 brew install watchmanを使用してBrewパッケージマネージャーを介してWatchmanをインストールすることです。 これは必ずしも必要ではありませんが、ReactNativeプロジェクト内の多くのファイルを処理する場合に役立ちます。

React Native:Sanestモバイルアプリケーション開発フレームワーク。
つぶやき

React Nativeをインストールするには、 npm install -g react-native-cliを使用してReactNativeコマンドラインアプリケーションをインストールする必要があります。 次に、 react-nativeコマンドを呼び出すと、新しいReactNativeアプリケーションを作成するのに役立ちます。 react-native init HelloWorldを実行すると、ボイラープレートコードを見つけることができるHelloWorldというフォルダーが作成されます。

ReactNativeの「HelloWorld」アプリのセットアップ方法を示すターミナルアニメーション。

Reactアプリケーションの変革

Reactが主要な機能であり、Reactライブラリのコア原則であるため、最小限のReact「HelloWorld」アプリケーションをReactNativeアプリケーションに変換するために必要なものを見てみましょう。

このコード例では、いくつかのES2015機能、特にクラスを使用しています。 React.createClassに固執するか、一般的なモジュールパターンと同様の関数フォームを使用することは完全に実行可能です。

 var React = require('react'); class HelloThere extends React.Component { clickMe() { alert('Hi!'); } render() { return ( <div className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</div> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));

ステップ1:CommonJSモジュールを採用する

最初のステップでは、Reactモジュールが代わりにreact-nativeを使用するように変更する必要があります。

 var React = require('react-native'); class HelloThere extends React.Component { clickMe() { alert('Hi!'); } render() { return ( <div className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</div> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));

React Webアプリケーションを開発するときに通常ツールパイプラインの一部となるのは、ReactNativeの不可欠な部分です。

ステップ2:DOMはありません

当然のことながら、モバイルにはDOMはありません。 以前に<div />を使用した場合は、 <View />を使用する必要があり、 <span />を使用した場合、ここで必要なコンポーネントは<Text />です。

 import React from 'react'; import {View, Text, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View className="box" onClick={this.clickMe.bind(this)}>Hello {this.props.name}. Please click me.</View> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));

テキストを<div />要素に直接配置するのは非常に便利ですが、ネイティブワールドでは、テキストを<View />に直接配置することはできません。 そのためには、 <Text />コンポーネントを挿入する必要があります。

 import React from 'react'; import {View, Text, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View className="box" onClick={this.clickMe.bind(this)}> <Text>Hello {this.props.name}. Please click me.</Text> </View> ); } } React.render(<HelloThere name="Component" />, document.getElementById('content'));

ステップ3:インラインスタイルは進むべき道です

React Nativeを使用すると、Webの世界でよく知られているfloatinline-blockをいじる代わりに、Flexboxモデリングを使用できます。 興味深いのは、ReactNativeがCSSを使用しないことです。

 import React from 'react'; import {View, Text, StyleSheet, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert('hi!'); } render() { return ( <View style={styles.box} onClick={this.clickMe.bind(this)}> <Text>Hello {this.props.name}. Please click me.</Text> </View> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));

インラインスタイルを使用することは、初心者には当惑するようです。 これは、JSXに直面し、以前はハンドルバーやJadeなどのテンプレートエンジンを使用していたときにReact開発者が経験しなければならなかった移行に似ています。

アイデアは、CSSを使用する方法でグローバルにスタイルシートを持っていないということです。 スタイルシートはコンポーネントレベルで直接宣言するため、コンポーネントの機能、作成するレイアウト、および適用するスタイルを確認するために必要なすべての情報があります。

 import React from 'react'; import {Text} from 'react-native'; var Headline = function(props) { this.render = () => <Text style={headlineStyle.text}>{props.caption}</Text>; }; var headlineStyles = StyleSheet.create({ text: { fontSize: 32, fontWeight: 'bold' } }); module.exports = Headline;

ステップ4:イベントの処理

Webページをクリックするのと同じことは、モバイルデバイスの要素をタップすることです。 要素をタップしたときに「アラート」がポップアップするようにコードを変更してみましょう。

 import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert("Hi!") } render() { return ( <TouchableOpacity onPress={this.clickMe()}> <View style={styles.box}> <Text>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));

<View />コンポーネントで直接利用できるイベントの代わりに、イベントをトリガーする要素を明示的に使用する必要があります。この場合、ビューを押したときのタッチイベントです。 利用可能なタッチ可能なコンポーネントにはさまざまなタイプがあり、それぞれが異なる視覚的フィードバックを提供します。

ステップ5:プラットフォーム間で動作をカスタマイズする

Platform.OSの値にアクセスすることで、ReactNativeアプリケーションが実行されているプラ​​ットフォームを検出できます。 上記の例で、実行しているプラ​​ットフォームに基づいて異なるアラートメッセージを表示したいとします。 私たちはこのようにそれを行うことができます:

 ... clickMe() { var message = ''; if(Platform.OS == 'ios') { message = 'Welcome to iOS!'; } else if(Platform.OS == 'android') { message = 'Welcome to Android!'; } Alert.alert(message); } ...

または、スイッチのような構文を提供するselectメソッドも使用できます。

 … clickMe() { Alert.alert(Platform.select({ ios: 'Welcome to iOS!', android: 'Welcome to Android!' }) ); } ...

ステップ6:カスタムフォントとreact-native link

カスタムフォントを追加するには、いくつかのフープをジャンプする必要があります。 まず、フォントのフルネームとフォントのファイル名が同じであることを確認します。iOSはフォントを取得するためにフォントのフルネームを使用しますが、Androidはファイル名を使用します。

したがって、フォントのフルネームがmyCustomFontの場合は、フォントのファイル名がmyCustomFont.ttfであることを確認してください。

その後、アセットフォルダーを作成し、npmをポイントする必要があります。 これを行うには、最初に、アプリケーションのルートディレクトリのassets/fontsの下にフォルダを作成します。 他のディレクトリでもかまいませんが、これはフォントディレクトリに使用される従来の名前です。

Reactのnpm統合セクションrnpmの下にAssetsプロパティを追加することで、アセットがある場所をnpmに伝えることができます。

 "rnpm": { "Assets": [ "./assets/fonts/" ] }

それがすべて終わったら、ついにreact-native linkを実行できます。 これにより、フォントが適切なディレクトリにコピーされ、iOSのinfo.plistに必要なxmlが追加されます。

完了したら、任意のスタイルシートでフルネームで参照するだけでフォントを使用できます。 Text要素で使用してみましょう。

 import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert("Hi!") } render() { return ( <TouchableOpacity onPress={this.clickMe()}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> ); } } var styles = StyleSheet.create({ box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 }, message: { fontFamily: 'myCustomFont' } }); React.render(<HelloThere name="Component" />, document.getElementById('content'));

ステップ7:物事を動かす

React Nativeは、コンポーネントのレイアウトにFlexboxと同じルールを使用します。 ボタンを画面の下部に配置したいとしますTouchableOpacityをコンテナでラップしましょう。 View

 <View style={styles.container}> <TouchableOpacity onPress={this.clickMe.bind(this)}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> </View>

次に、すでに定義されている他のスタイルとともに、 containerスタイルを定義しましょう。

 container: { flex: 1, justifyContent: 'center', alignItems: 'center' }

justifyContentalignItemsに焦点を当てましょう。 これらの2つのプロパティは、コンポーネントがそれぞれ主軸と副軸に沿ってどのように配置されるかを制御します。 デフォルトでは、主軸は垂直軸であり、副軸は水平軸です( flexDirectionプロパティをrowに設定することで変更できます)。

justifyContentには、次のように設定できる6つの可能な値があります。

  • flex-startは、コンポーネントのバウンディングボックスの先頭に、すべての要素を一緒に配置します。
  • flex-endは、すべての要素を最後に配置します。
  • centerは、すべての要素をバウンディングボックスの中央に配置します。
  • space-aroundはコンポーネントを均等に広げ、作成されたバウンディングボックスの中央にコンポーネントを配置します。
  • space-evenlyはコンポーネントも均等に広げますが、コンポーネントと他の境界の間に同じ量のスペースを残そうとします。
  • space-betweenは、隣接するコンポーネント間の間隔を等しく保つことにより、コンポーネントを広げます。

alignItemsは、flex flex-startflex-endcenterstretchの4つの可能な値に設定できます。 最初の3つは、 justifyContentの場合と同じように動作しますが、 stretchは、軸に沿って使用可能なすべてのスペースを占めるようにコンポーネントを設定し、軸が完全に塗りつぶされるようにします。

したがって、 TouchableOpacityを下部に表示し、水平軸に沿って中央に配置する必要があるため、次のようにスタイルを変更できます。

 container: { flex: 1, justifyContent: 'flex-end', alignItems: 'center' }

justifyContentalignItemsの値の詳細については、こことここを参照してください。

ステップ8:アプリケーションを登録する

ブラウザー用にReactを使用して開発する場合は、マウントポイントを定義し、 React.renderを呼び出して、Reactにその魔法を実行させる必要があります。 React Nativeでは、これは少し異なります。

 import React from 'react'; import {View, Text, StyleSheet, TouchableOpacity, Alert, Platform} from 'react-native'; class HelloThere extends React.Component { clickMe() { Alert.alert(Platform.select({ ios: 'Welcome to iOS!', android: 'Welcome to Android!' })); } render() { return ( <View style={styles.container}> <TouchableOpacity onPress={this.clickMe.bind(this)}> <View style={styles.box}> <Text style={styles.message}>Hello {this.props.name}. Please click me.</Text> </View> </TouchableOpacity> </View> ); } } var styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'flex-start', alignItems: 'center' }, box: { borderColor: 'red', backgroundColor: '#fff', borderWidth: 1, padding: 10, width: 100, height: 100 }, message: { fontFamily: 'myCustomFont' } }); var MainComponent = function() { this.render = function() { return <HelloThere name="Component" />; } }; AppRegistry.registerComponent('MainComponent', function() { return MainComponent; });

AppRegistryオブジェクトを使用して行われるObjective-C側のコンポーネントを登録する必要があります。 付ける名前は、Xcodeプロジェクト内の名前と一致する必要があります。

Hello World React Nativeアプリケーションには、対応するWebアプリケーションよりも大幅に多くのコード行がありますが、一方で、React Nativeは、特にスタイルがコンポーネントで定義されているため、関心の分離をもう少し進めます。

ちなみに、特にReact(Native)アプリケーションが少し複雑になった場合は、 renderメソッドでclickMeメソッドをthisコンテキストに再バインドしないでください。 これは、レンダリング呼び出しごとにメソッドを再バインドしますが、これは非常に多くなる可能性があります。 別の方法は、コンストラクター内でメソッドをバインドすることです。

アプリケーションの実行

アプリケーションを実行するには、 index.ios.jsファイルの内容を、最後の手順で変換したアプリケーションのコードに置き換える必要があります。 次に、Xcodeプロジェクトを開き、大きな実行ボタンを押す必要があります。 まず、React Nativeサーバーでターミナルが開き、次にシミュレーターウィンドウが表示されます。 React Nativeサーバーはバンドルを作成し、ネイティブアプリケーションがそれをフェッチします。 これにより、Web開発のような迅速な開発サイクルが可能になり、変更はほぼ瞬時にシミュレーターに反映されます。

Androidの場合、 scriptsの下のpackage.jsonファイルに以下を追加するだけで十分です。

 "android-linux": "react-native bundle --platform android --dev false --entry-file index.ios.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/ main/res && react-native run-android"

次に、 npm run android-linuxます。 android/app/src/main/assetsディレクトリが事前に存在することを確認してください。

ターミナルがポップアップすると、アプリケーションがシミュレーターに表示されます。 CMD + Dを押すと、開発メニューが表示されます。 ボックスをクリックすると、アラートが表示されます。 iOSバージョン:

「こんにちは」というアラートポップアップが表示されたAppleの電話。

そしてAndroidは次のようなものをレンダリングします:

「こんにちは」というアラートポップアップが表示されたAndroidスマートフォン。

配布の場合、ローカル開発サーバーを指すアプリケーションを使用してもうまくいきません。 このため、コマンドreact-native bundleを使用して、ReactNativeサーバーが実行されていないときに使用するバンドルを作成できます。 その場合、オフラインバンドルを使用するには、 AppDelegatedidFinishLaunchingWithOptionsメソッドを更新する必要があります。

このサンプルアプリケーションはGithubでも入手できます。

ReactNativeでの作業

言及する価値のあるもう1つの点は、モバイルアプリケーションにReactの概念とJavaScriptを使用するだけでなく、Web開発者が慣れているワークフローの一部をReactNativeでも使用できることです。 Web開発から来るとき、私たちはツールの開発、要素の検査、およびライブリロードに慣れています。

React Nativeが機能する方法は、すべてのJavaScriptファイルをバンドルに入れることです。 このバンドルは、サーバーから提供されるか、アプリケーションと一緒にバンドルされます。 1つ目は、ライブリロードを有効にできるため、シミュレーターでの開発に非常に役立ちます。 Reactが提供する開発者メニューはChrome開発者ツールほど強力ではありませんが、Chrome(またはSafari)開発者/デバッガツールを使用したライブリロードとデバッグで非常にWebのような開発者エクスペリエンスを提供します。

Web開発者は、迅速なWebテストのためのオンラインプレイグラウンドであるJSFiddleまたはJSBinに精通しています。 WebブラウザーでReactNativeを試すことができる同様の環境があります。

React Native:堅実でモダンな選択

私は当初、ReactNativeに対してより慎重なアプローチを提案していました。 今日、それは成熟した確かな選択です。

Reactの大きな利点の1つは、ビューレイヤーを表すだけなので、ワークフローに影響を与えないことです。 独自のGruntパイプラインを定義しますか? それともWebpackを使用しますか? また、モデルのニーズにBackbone.jsを使用しますか? それとも、プレーンなJavaScriptオブジェクトを使用しますか? Reactはこれらの選択に制限を設けていないため、これらすべての質問に対する答えは完全にあなた次第です。 公式サイトが述べているように、「Reactは残りのテクノロジースタックについて何も想定していないので、既存のプロジェクトの小さな機能で簡単に試すことができます。」

ある程度、これはReactNativeにも当てはまります。 モバイル開発者は、アプリケーションの一部としてReact Nativeを統合し、Webに触発された開発ワークフローを利用し、必要に応じてライブラリをより大規模に統合することを選択できます。

いずれにせよ、確かなことが1つあります。それは、ReactNativeがなくなることはないということです。 Facebookは、アプリストアに複数のReactNativeを利用したアプリケーションを持っていることに大きな利害関係を持っています。 React Nativeを取り巻くコミュニティは巨大であり、成長を続けています。

関連: QRスキャナーの構築:ReactNativeCameraチュートリアル