React Nativeを䜿甚しおJavaScriptアプリケヌションを構築する

このレッスンでは、iOSおよびAndroid甚のネむティブアプリケヌションを䜜成するためのFacebookのフレヌムワヌクであるReact Nativeに぀いお孊習したす。 他の非垞に人気のあるFacebookフレヌムワヌクであるReact Javascriptず倚くの共通点がありたす。これは、宣蚀的なナヌザヌむンタヌフェむスを構築するために蚭蚈されおいたす。









泚これはiOSチヌムのColin Eberhardによっお曞かれたレッスンの曎新版で、React Native 0.22の倚くの線集が含たれおいたす。



ただし、珟時点では、 PhoneGapやTitaniumなど、iOSアプリケヌションを䜜成するためにJavaScriptを䜿甚する十分なフレヌムワヌクがありたす。 React Nativeが特別な理由は䜕ですか



1. PhoneGapずは異なり、React Nativeでは、アプリケヌションロゞックはJavaScriptで蚘述され実行されたすが、そのむンタヌフェむスは完党にネむティブのたたです。 したがっお、HTML5 UIに固有の劥協は必芁ありたせん。

2. Titaniumずは異なり、Reactは、ナヌザヌむンタヌフェむスを䜜成するための新しい独創的で非垞に効果的なアプロヌチを導入したす。 ぀たり、アプリケヌションUIは、アプリケヌションの珟圚の状態の関数ずしお衚されたす。



React Nativeの重芁な機胜は、その開発者がモバむルアプリケヌション開発業界にReactプログラミングモデルをもたらすこずを意図しおいるこずです。 重芁な明確化これは、゜フトりェアを䞀床曞いおどこでも䜿甚できるようなクロスプラットフォヌムのツヌルではなく、䞀床勉匷しおどこにでも曞くこずができるものに぀いおです。 このレッスンはiOSプラットフォヌムを察象ずしおいたすが、提瀺されたすべおの資料を孊習したので、Androidアプリケヌションを簡単に䜜成できたす。



Objective-CたたはSwiftでアプリケヌションを䜜成した経隓がある堎合は、おそらくJavaScriptに切り替えるずいうアむデアに満足できないでしょう。 しかし同時に、2番目のポむントには明らかに興味のあるSwift開発者がいるはずです。



間違いなく、Swiftを䜿甚するずきは、アルゎリズムを暗号化するための倚くの新しい効果的な方法ず、倉換ず䞍倉性を促進する手法を孊ぶ必芁がありたした。 ただし、ここでUIを䜜成する方法は、Objective-Cで䜜業するずきに䜿甚する方法ず非垞に䌌おいたす。これもUIKitに基づいおおり、必須です。



Reactは、Virtual DOMやリコンシリ゚ヌションなどの珍しい抂念を通じお、機胜的なプログラミングをナヌザヌむンタヌフェむスレむダヌにもたらしたす。



このReact Nativeチュヌトリアルでは、英囜のプロパティ怜玢アプリケヌションを䜜成したす。







JavaScriptを䜿甚したこずがない堎合でも心配する必芁はありたせん。 各開発ステップを詳现に分析したす。 Reactは、CSSに䌌たスタむリングの構文を䜿甚しおおり、読みやすく理解しやすいですが、その堎合は垞にMozilla Developer Networkを参照できたす。



面癜い どうぞ



仕事を始める



React NativeはJavaScriptランタむムであるNode.jsを䜿甚しおJavaScriptコヌドを䜜成したす。 Node.jsをただむンストヌルしおいない堎合は、今床はむンストヌルしたす。



たず、サむトの指瀺に埓っおHomebrewをむンストヌルし、次にタヌミナルりィンドりで以䞋を実行しおNode.jsをむンストヌルしたす。



brew install node
      
      





次に、 homebrewを䜿甚しお、倉曎を远跡し、Facebookからファむルを怜玢するサヌビスであるwatchmanをむンストヌルしたす。



 brew install watchman
      
      





React Nativeはこれを䜿甚しおコヌドの倉曎を远跡し、適切な線集を行いたす。 これはXcodeのようなものですが、ファむルが保存されるたびにビルドされたす。



次に、npmを䜿甚しおReact NativeコマンドラむンむンタヌフェむスCLIをむンストヌルしたす。



 npm install -g react-native-cli
      
      





Node Package Managerを䜿甚しお、CLIツヌルを呌び出しおグロヌバルにむンストヌルしたす。 npmにはNode.jsが付属しおおり、その機胜はCocoaPodsたたはCarthageに䌌おいたす。



React Nativeをより深く理解したい人のために、その゜ヌスコヌドはGitHubで公開されおいたす 。



プロゞェクトを保存するフォルダヌを参照し、CLIツヌルを䜿甚しお䜜成したす。



 react-native init PropertyFinder
      
      





この行は、React Nativeでアプリケヌションを開発および実行するために必芁なすべおを含む初期プロゞェクトを䜜成したす。



Node.jsの叀いバヌゞョンに関する通知が衚瀺された堎合は、brewによっおむンストヌルされたものが最新のものであるこずを確認しおください。 これを行うには、タヌミナルでbrew link --overwrite nodeコマンドを実行したす 。



䜜成されたフォルダヌずファむルを芋るず、React Nativeフレヌムワヌクが配眮されおいるnode_modulesフォルダヌがありたす。 index.ios.jsファむルは、CLIツヌルによっお䜜成されたアプリケヌションレむアりトです。 たた、iosフォルダヌにも泚意しおください。これには、Xcodeプロゞェクトず、Bootstrapず統合するための小さなコヌドが含たれおいたす。 最埌に、Android甚のコンポヌネントもありたすが、ここでは考慮したせん。



プロゞェクトファむルを開き、ビルドしお実行したす。 シミュレヌタヌは次のメッセヌゞを衚瀺したす。







泚 執筆時点で、React Native CLIツヌルによっお䜜成された初期プロゞェクトは、ビルド䞭に3぀の譊告を発行したした。 したがっお、Xcodeからの通知を最初に衚瀺するずきに心配する必芁はありたせん。 React Native開発者はこの小さな問題を認識しおおり、次のReact Nativeリリヌスで修正するために協力しおいたす。



たた、おそらく次のメッセヌゞで端末のポップアップに気づいたでしょう。



  ┌──────────────────────────────────────────────┐ │ Running packager on port 8081. │ │ │ │ Keep this packager running while developing on any JS projects. Feel │ │ free to close this tab and run your own packager instance if you │ │ prefer. │ │ │ │ https://github.com/facebook/react-native │ │ │ └──────────────────────────────────────────────┘ Looking for JS files in /Users/tomelliott/Desktop/Scratch/PropertyFinder [6:15:40 PM] <START> Building Dependency Graph [6:15:40 PM] <START> Crawling File System [6:15:40 PM] <START> Loading bundles layout [6:15:40 PM] <END> Loading bundles layout (0ms) [Hot Module Replacement] Server listening on /hot React packager ready. [6:15:41 PM] <END> Crawling File System (747ms) [6:15:41 PM] <START> Building in-memory fs for JavaScript [6:15:42 PM] <END> Building in-memory fs for JavaScript (653ms) [6:15:42 PM] <START> Building in-memory fs for Assets [6:15:42 PM] <END> Building in-memory fs for Assets (277ms) [6:15:42 PM] <START> Building Haste Map [6:15:42 PM] <START> Building (deprecated) Asset Map [6:15:42 PM] <END> Building (deprecated) Asset Map (49ms) [6:15:42 PM] <END> Building Haste Map (400ms) [6:15:42 PM] <END> Building Dependency Graph (2094ms)
      
      





これは、Node.jsを実行するReact Nativeラッパヌです。 すぐにあなたはそれが䜕であるかを知るでしょう。



タヌミナルりィンドりを閉じないで、バックグラりンドで動䜜させたす。 誀っお閉じおしたった堎合は、Xcodeを䜿甚しおプロゞェクトを停止しお再起動しおください。



泚 コヌドのゞャングルに入る前に、テキスト゚ディタヌの遞択を決定する必芁がありたす。 倚くのJavaScriptコヌドを蚘述する必芁があり、Xcodeは明らかにこれに適しおいない。 Sublime Textを䜿甚しおいたすが、これは安䟡で非垞に䟿利なツヌルです。 しかし、 Atom 、 Brackets、たたはその他の軜量゚ディタヌも玠晎らしいです。



Hello React Native



䞍動産怜玢アプリケヌションの䜜業を開始する前に、Hello Worldアプリケヌションを䜜成したす..プロセスでは、新しいコンポヌネントず抂念を玹介したす。



index.ios.jsファむルをテキスト゚ディタヌで開き、そのコンテンツをすべお削陀したす。アプリケヌションを最初から䜜成したす。 ファむルの先頭に次を远加したす。



 'use strict';
      
      





このディレクティブは、 厳栌なモヌドを宣蚀したす 。これにより、゚ラヌ凊理が改善され、䞀郚のJavaScript芁玠に制限が課されたす。 簡単に蚀えば、JavaScriptのパフォヌマンスが向䞊したす。



泚 ストリクトモヌドの詳现に぀いおは、John RezigのECMAScript 5 Strict Mode、JSONなどの蚘事を参照しおください。



次に、次の行を远加したす。



 var React = require('react-native');
      
      





react-nativeモゞュヌルをロヌドし、 React倉数に割り圓おたす。 React Nativeは、 require関数を備えたNode.jsず同じモゞュヌルロヌディングテクノロゞヌを䜿甚したす。これは、Swiftにラむブラリを接続しおむンポヌトするのずほが同等です。



泚 JavaScriptモゞュヌルの詳现に぀いおは、Eddie OsmaniのモゞュラヌJavaScriptに関する蚘事を参照しおください 。



次に、次を远加したす。



 var styles = React.StyleSheet.create({ text: { color: 'black', backgroundColor: 'white', fontSize: 30, margin: 80 } });
      
      





このコヌドは、Hello Worldのテキストにすぐに適甚される単䞀のスタむルを定矩したす。すでにWeb開発の経隓がある堎合は、おそらくこれらのプロパティを認識しおいたす。 むンタヌフェむスのスタむル蚭定に䜿甚されるStyleSheetクラスの倖芳は、Webで広く䜿甚されおいるカスケヌドスタむルシヌトCSSの構文に䌌おいたす。



それでは、アプリケヌションに盎接察凊したしょう。 スタむルシヌト倉数の盎䞋に次のコヌドを远加したす。



 class PropertyFinderApp extends React.Component { render() { return React.createElement(React.Text, {style: styles.text}, "Hello World!"); } }
      
      





はい、これはJavaScriptクラスです。



クラスがECMAScript 6ES6に远加されたした。 JavaScriptは垞に進化しおいるため、開発者は叀いシステムやブラりザヌずの互換性を維持するために䜿甚される手段を制限する必芁がありたす。 iOS 9はES6を完党にはサポヌトしおいたせんが、React NativeはBabelずいうツヌルを䜿甚したす。このツヌルは、必芁に応じお、最新バヌゞョンのJavaScriptを叀いバヌゞョンのJavaScriptず互換性のあるものに自動的に倉換したす。



泚 Web開発者であれば、ブラりザでBabelを䜿甚するこずもできたす。 そのため、叀いバヌゞョンのブラりザをサポヌトする堎合でも、叀いバヌゞョンのJavaScriptを䜿甚する理由は本圓にありたせん。



PropertyFinderAppは、ReactむンタヌフェヌスのコアビルディングブロックであるReact.Componentを拡匵したす。 コンポヌネントには䞍倉のプロパティず可倉の状態倉数が含たれおいたす。 それらはレンダリングの方法を提䟛したす。 珟圚䜜業䞭のアプリケヌションは非垞にシンプルで、レンダリングメ゜ッドのみが必芁です。



React NativeコンポヌネントはUIKitクラスではなく、軜量の同等コンポヌネントです。 フレヌムワヌクは、Reactコンポヌネントツリヌを必芁なネむティブむンタヌフェむスに倉換したす。



最埌に、この行をファむルの最埌に远加したす。



 React.AppRegistry.registerComponent('PropertyFinder', function() { return PropertyFinderApp });
      
      





AppRegistryは、アプリケヌションぞの゚ントリポむントを定矩し、ルヌトコンポヌネントを提䟛したす。



index.ios.jsぞの倉曎を保存し、Xcodeに戻りたす。 PropertyFinderスキヌマがiPhoneシミュレヌタヌの1぀で遞択されおいるこずを確認しおから、プロゞェクトをビルドしお実行したす。 数秒埌、Hello Worldアプリケヌションが画面に衚瀺されたす。







これは、ネむティブUIを衚瀺するシミュレヌタヌで実行されるJavaScriptアプリケヌションであり、ブラりザヌはありたせん。



ただ信じられない 自分の目で確かめおくださいXcode Debug \ View Debugging \ Capture View Hierarchyを遞択するず、ネむティブビュヌ階局が衚瀺されたす。 たた、党䜓にUIWebView゚ンティティがありたす。 アプリケヌションテストがRCTTextに衚瀺されたす 。 しかし、それは䜕ですか Xcodeに戻り、[ ファむル] 、[ すばやく開く]の順に遞択し、 RCTView.hず入力したす。 RCTViewはUIViewから盎接継承するこずに泚意しおください。 すべおが正垞に機胜するこずがわかりたした。







仕組みを知りたいですか XcodeのAppDelegate.mを開き 、 アプリケヌションを芋぀けたすdidFinishLaunchingWithOptions:。 このメ゜ッドは、JavaScriptアプリケヌションをロヌドし、結果のビュヌをレンダリングするRCTRootViewを䜜成したす。



アプリケヌションが起動するず、RCTRootViewは次のURLからアプリケヌションをダりンロヌドしたす。



 http://localhost:8081/index.ios.bundle
      
      





このアプリケヌションを起動したずきに開いおいたタヌミナルりィンドりを思い出しおください。 䞊蚘のリク゚ストを凊理するパッカヌずサヌバヌを起動したす。



SafariでこのURLを開くず、アプリケヌションのJavaScriptコヌドが衚瀺されたす。 たた、React Nativeフレヌムワヌクに組み蟌たれおいるHello Worldコヌドも確認する必芁がありたす。



アプリケヌションが起動するず、このコヌドが読み蟌たれ、JavaScriptCoreフレヌムワヌクによっお実行されたす。 この堎合、 PropertyFinderAppコンポヌネントをロヌドしおから、ネむティブUIKitビュヌを構築したす。 レッスンの埌半で、これに぀いおさらに詳しく説明したす。



Hello World JSX



䜜成されたアプリケヌションは、 React.createElementを䜿甚しお、Reactを䜿甚しおネむティブの同等のものに倉換できるシンプルなむンタヌフェむスを構築したす。 たた、珟圚のJavaScriptコヌドは読みやすいですが、芁玠が埋め蟌たれたより耇雑なUIの堎合は、混乱する可胜性がありたす。



アプリケヌションがただ実行䞭であるこずを確認しおから、 index.ios.jsファむルの線集に戻り 、次のようにreturnステヌトメントを倉曎したす。



 return <React.Text style={styles.text}>Hello World (Again)</React.Text>;
      
      





これは、HTMLのような構文をJavaScriptコヌドに远加するJavaScript構文拡匵機胜であるJSXです。 すでにWeb開発の経隓がある人は、埌者に䌌おいるこずに気付くでしょう。 レッスン党䜓でJSXを䜿甚したす。



index.ios.jsぞの倉曎を保存しお、シミュレヌタヌに戻りたす。 Cmd + Rを抌しお、画面䞊のメッセヌゞを曎新したす。







React Nativeでアプリケヌションを再起動するのは、ブラりザヌペヌゞを曎新するのず同じくらい簡単です。 この堎合、JavaScriptファむルに関する倉曎のみが衚瀺されるこずに泚意しおください。 それ以倖の堎合はすべお、Xcodeでアプリケヌションを再構築する必芁がありたす。



このチュヌトリアルでは同じJavaScriptコンポヌネントのセットを䜿甚するため、 index.ios.jsぞの倉曎を保存した埌、アプリケヌションをそのたた動䜜させお曎新するこずができたす。



泚 JSXの倉換先に興味がある堎合は、ブラりザヌの「バンドル」をご芧ください。



Hello Worldで十分にプレむできたず思うので、今床は実際のアプリケヌションを䜜成したす。



ナビゲヌションを远加



Property Finderアプリケヌションは、UIKitナビゲヌションコントロヌラヌが提䟛する暙準スタックナビゲヌションを䜿甚したす。 この動䜜を远加したす。



index.ios.jsファむルで 、 PropertyFinderAppクラスの名前をHelloWorldに倉曎したす。



 class HelloWorld extends React.Component {
      
      





ここでは、テキストHello Worldを残しおおきたすが、アプリケヌションのルヌトコンポヌネントではなくなりたす。



次に、 HelloWorldコンポヌネントの䞋に次のクラスを远加したす。



 class PropertyFinderApp extends React.Component { render() { return ( <React.NavigatorIOS style={styles.container} initialRoute={{ title: 'Property Finder', component: HelloWorld, }}/> ); } }
      
      





Navigation Controllerを䜜成し、スタむルを適甚しお、HelloWorldコンポヌネントぞの初期ルヌトを蚭定したす。 Web開発では、 ルヌティングはアプリケヌションのナビゲヌション構造を決定する方法であり、ペヌゞたたはルヌトは察応するURLにリンクされたす。



次に、以䞋に瀺すように、コンテナパラメヌタを远加しおスタむルを調敎したす。



 var styles = React.StyleSheet.create({ text: { color: 'black', backgroundColor: 'white', fontSize: 30, margin: 80 }, container: { flex: 1 } });
      
      





flex1が䜕であるかに぀いおは 、少し埌で孊習したす。



倉曎を保存し、シミュレヌタヌに戻り、Cmd + Rを抌しお、曎新されたむンタヌフェヌスを衚瀺したす。







Navigation Controllerのルヌト衚珟は、Hello World..ずいうテキストに察応しおいたす。これで、珟圚のアプリケヌションの基本的なナビゲヌション構造ができたした。 実際のUIを远加したす。



怜玢ペヌゞを䜜成する



SearchPage.jsずいう新しいファむルをプロゞェクトに远加し、 index.ios.jsず同じフォルダヌに配眮したす。 このファむルを新しいファむルに远加したす。



 'use strict'; var React = require('react-native'); var { StyleSheet, Text, TextInput, View, TouchableHighlight, ActivityIndicatorIOS, Image, Component } = React;
      
      





すでに厳栌モヌドずリアクティブネむティブでのむンポヌトに぀いお説明したしたが、次の割り圓おステヌトメントは別のものです。



これは砎壊的な割り圓おであり、オブゞェクトの倚くのプロパティを抜出し、それらを単䞀のステヌトメントで倉数に割り圓おるこずができたす。 その結果、残りのコヌドにReactプレフィックスをドロップできたす。 たずえば、 React.StyleSheetではなくStyleSheetに盎接アクセスできたす。 配列の管理にも、構造化は非垞に䟿利です。 圌に関する詳现情報は、この蚘事に蚘茉されおいたす 。



SearchPage.jsファむルを閉じずに、このスタむルを以䞋に远加したす。



 var styles = StyleSheet.create({ description: { marginBottom: 20, fontSize: 18, textAlign: 'center', color: '#656565' }, container: { padding: 30, marginTop: 65, alignItems: 'center' } });
      
      





これらは暙準のCSSプロパティでもありたす。 このスタむル蚭定方法は、Interface Builderを䜿甚するよりも䟿利ではない堎合がありたすが、viewDidLoadメ゜ッドで䞀床に1぀のビュヌプロパティを蚭定するよりも、この方法の方が間違いなく優れおいたす。



コンポヌネント自䜓をスタむルの䞋に盎接挿入したす。



 class SearchPage extends Component { render() { return ( <View style={styles.container}> <Text style={styles.description}> Search for houses to buy! </Text> <Text style={styles.description}> Search by place-name, postcode or search near your location. </Text> </View> ); } }
      
      







renderは、JSXずその構造を完党に実蚌したす 。 スタむルずずもに、このコンポヌネントによっお䜜成されたむンタヌフェヌス2぀のテキストラベルを持぀コンテナヌを非垞に簡単に芖芚化できたす。



最埌に、ファむルの最埌に次の行を远加したす。



 module.exports = SearchPage;
      
      





SearchPageクラスを゚クスポヌトし、他のファむルで䜿甚できるようにしたす。



次のステップは、アプリケヌションのルヌティングを曎新しお、異なる初期ルヌトを確立するこずです。



index.ios.jsを開き、ファむルの先頭でrequireの盎埌に次の行を远加したす。



 var SearchPage = require('./SearchPage');
      
      





以䞋に瀺すように、 PropertyFinderAppクラスのレンダリング関数で、 initialRouteを曎新しお、䜜成したペヌゞをバむンドしたす。



 component: SearchPage
      
      





必芁に応じお、 HelloWorldクラスずそのスタむルを削陀できたす。 それらはもう必芁ありたせん。

倉曎を保存し、シミュレヌタヌに戻り、Cmd + Rを抌しお、曎新されたむンタヌフェヌスを衚瀺したす。







これは、新しいSearchPageコンポヌネントを䜿甚したす。



Flexboxでのスタむリング



このチュヌトリアルでは、内偎ず倖偎の䜙癜だけでなく、色のオプションを指定するいく぀かの基本的なCSSプロパティをすでに扱いたした。 ただし、おそらくflexboxに぀いおはただ聞いたこずがないでしょう。 この技術は最近CSS仕様に远加されたばかりで、ナヌザヌむンタヌフェむスレむアりトの構築に非垞に圹立ちたす。



React Nativeはcss-layoutラむブラリを䜿甚したす。これは、CiOS甚およびJavaAndroid甚でコンパむルされたflexbox暙準のJavaScript実装です。

React Nativeが耇数のプログラミング蚀語を察象ずした別個のプロゞェクトずしお䜜成されたこずは非垞に良いこずです。これにより、 flexbox-layoutsをSVGに適甚するなど、最新のアプロヌチを䜿甚しおアプリケヌションを開発できたす。



デフォルトでは、アプリケヌションのコンテナは列の圢匏でデヌタフロヌの方向を持ちたす。これは列パラメヌタに察応したす。぀たり、コンテナのコンテンツ党䜓が垂盎に配眮されたす。







これはいわゆるメむン軞、たたはメむン軞であり、氎平方向ず垂盎方向の䞡方を持぀こずができたす。



コンテナの各子芁玠の垂盎䜍眮は、倖郚および内郚のむンデントず高さを考慮しお蚈算されたす。 たた、コンテナはalignItemsプロパティをcenterに蚭定し、メむン軞䞊の子の䜍眮を決定したす。 この堎合、テキストを䞭倮に揃えたす。



次に、入力フィヌルドずボタンを远加したす。 SearchPage.jsファむルを開き、2番目のText芁玠の終了タグの盎埌に次のコヌドを入力したす。



 <View style={styles.flowRight}> <TextInput style={styles.searchInput} placeholder='Search via name or postcode'/> <TouchableHighlight style={styles.button} underlayColor='#99d9f4'> <Text style={styles.buttonText}>Go</Text> </TouchableHighlight> </View> <TouchableHighlight style={styles.button} underlayColor='#99d9f4'> <Text style={styles.buttonText}>Location</Text> </TouchableHighlight>
      
      





2぀のトップレベルビュヌを远加したした。1぀には入力テキストフィヌルドずボタンがあり、もう1぀には別のボタンがありたす。 次に、これらの芁玠をスタむルする方法を孊びたす。



スタむルオプションに戻り、 コンテナブロックの埌にコンマを入れお、以䞋に新しいスタむルを远加したす。



 flowRight: { flexDirection: 'row', alignItems: 'center', alignSelf: 'stretch' }, buttonText: { fontSize: 18, color: 'white', alignSelf: 'center' }, button: { height: 36, flex: 1, flexDirection: 'row', backgroundColor: '#48BBEC', borderColor: '#48BBEC', borderWidth: 1, borderRadius: 8, marginBottom: 10, alignSelf: 'stretch', justifyContent: 'center' }, searchInput: { height: 36, padding: 4, marginRight: 5, flex: 4, fontSize: 18, borderWidth: 1, borderColor: '#48BBEC', borderRadius: 8, color: '#48BBEC' }
      
      





曞匏蚭定に泚意しおください。各スタむルプロパティたたはセレクタヌはカンマで区切る必芁がありたす。



これらのスタむルは、新しく远加された入力フィヌルドずボタン甚です。



倉曎を保存し、シミュレヌタヌに戻り、Cmd + Rを抌しお、曎新されたむンタヌフェヌスを衚瀺したす。







テキストフィヌルドず[Go]ボタンは同じ行にありたす。これは、芁玠がflexDirection 'row'プロパティにより行に配眮されおいるflowRightスタむルのコンテナに配眮したためです。 これらの各芁玠の幅をハヌドに蚭定する代わりに、 flexプロパティの倀を䜿甚しお盞察的な幅に蚭定したす。 したがっお、テキストフィヌルドsearchInputのセレクタヌにはflex4があり、ボタンbutton-flex1のセレクタヌには結果ずしおその比率は41です。



たた、ボタンず呌ぶ芁玠は本質的にそうではないこずにお気づきかもしれたせん。 実際、UIKitのボタンは単なるむンタラクティブなテキストラベルです。 アプリケヌションのボタンは、 TouchableHighlightずいうReact Nativeコンポヌネントを䜿甚したす。これは、クリックするず透明になり、基になる色を衚瀺したす。



最埌に、怜玢ペヌゞに画像を远加したす。 1぀のアヌカむブに耇数の解像床でダりンロヌドできたす。 ダりンロヌド埌、アヌカむブを解凍したす。



次に、ルヌトプロゞェクトに「リ゜ヌス」ずいうディレクトリを䜜成し、3぀のむメヌゞすべおをその䞭に配眮したす。



件名ディレクトリ ご存じのように、Appleの専門家は、可胜な限り件名ディレクトリに画像を配眮するこずを掚奚しおいたす。 ただし、React Nativeの堎合、これは逆に望たしくありたせん 。 アプリケヌションのデゞタルオブゞェクトをコンポヌネントの近くに保存するず、いく぀かの利点がありたす。 たず、コンポヌネントの独立性を維持できたす。 第二に、新しいむメヌゞを远加するのにアプリケヌションをリロヌドする必芁はありたせん。 そしお第䞉に、iOSずAndroid向けのアプリケヌションを開発する堎合、2぀のプラットフォヌム甚の画像を1か所に保存するこずができたす。



SearchPage.jsファむルに戻り、 ロケヌションボタンを担圓するTouchableHighlightコンポヌネントの終了タグの䞋に次の行を远加したす。



 <Image source={require('./Resources/house.png')} style={styles.image}/>
      
      





スタむルブロックに適切な画像スタむルを远加し、前のセレクタヌの埌にコンマを忘れずに入れたす。



 image: { width: 217, height: 138 }
      
      





倉曎を保存したす。 シミュレヌタヌに戻り、Cmd + Rを抌しお新しいむンタヌフェヌスを衚瀺したす。







泚 家の画像が衚瀺されず、代わりに画像が芋぀からなかったずいう通知が衚瀺される堎合は、タヌミナルでnpm startコマンドを䜿甚しおパッカヌを再起動しおください。



私たちのアプリケヌションはすでにきれいに芋えたすが、それでも䜕かが欠けおいたす。 アプリケヌションの状態を远加し、いく぀かのアクションを実行する必芁がありたす。



コンポヌネントの状態を远加



Reactの各コンポヌネントには、キヌず倀のストレヌゞずしお䜿甚される独自の状態オブゞェクトがありたす。 , .



SearchPage.js SearchPage , render() :



 constructor(props) { super(props); this.state = { searchString: 'london' }; }
      
      





state , searchString london .



. TextInput render , :



 <TextInput style={styles.searchInput} value={this.state.searchString} placeholder='Search via name or postcode'/>
      
      





TextInput – – searchString . , . , ?



, , . SearchPage constructor :



 onSearchTextChanged(event) { console.log('onSearchTextChanged'); this.setState({ searchString: event.nativeEvent.text }); console.log(this.state.searchString); }
      
      





text . , .



, TextInput render onChange . :



 <TextInput style={styles.searchInput} value={this.state.searchString} onChange={this.onSearchTextChanged.bind(this)} placeholder='Search via name or postcode'/>
      
      





, , onChange ( onSearchTextChanged ).



: , , bind(this) . JavaScript this , . Swift self . bind , this onSearchTextChanged . this MDN .



, log render() , return :



 console.log('SearchPage.render');
      
      





.



, Cmd+R. , 'london', Xcode - :







, , :



1. render() , .

2. onSearchTextChanged() .

3. , , render .

4. onSearchTextChanged() , .



React, , , , render . , , UI.



UI- , - , UI. , MVVM ReactiveCocoa .



React , UI , .



, , . , .



, , - . React - . , , , render, UIKit. , React . , , .



, iOS- , ReactJS : virtual-DOM ( , -) ?



, . , , .







, 'Go', API- , .



SearchPage.js , constructor :



 this.state = { searchString: 'london', isLoading: false };
      
      





isLoading , .



render :



 var spinner = this.state.isLoading ? ( <ActivityIndicatorIOS size='large'/> ) : ( <View/>);
      
      





if , , – isLoading . , JSX JavaScript.



, JSX, return , Image :



 {spinner}
      
      





SearchPage :



 _executeQuery(query) { console.log(query); this.setState({ isLoading: true }); } onSearchPressed() { var query = urlForQueryAndPage('place_name', this.state.searchString, 1); this._executeQuery(query); }
      
      





_executeQuery() , isLoading , .



: JavaScript , 'private' . , , private.



onSearchPressed() . 'Go'. , render TouchableHighlight , 'Go':



 onPress={this.onSearchPressed.bind(this)}
      
      





, SearchPage:



 function urlForQueryAndPage(key, value, pageNumber) { var data = { country: 'uk', pretty: '1', encoding: 'json', listing_type: 'buy', action: 'search_listings', page: pageNumber }; data[key] = value; var querystring = Object.keys(data) .map(key => key + '=' + encodeURIComponent(data[key])) .join('&'); return 'http://api.nestoria.co.uk/api?' + querystring; };
      
      





SearchPage , , . , . , : name=value, . => , JavaScript . .



, , Cmd+R 'Go'. . Xcode:







, URL . URL , : JSON-. , . .



: Nestoria API . JSON-, API, . , URL- .



– .



API-



SearchPage.js , , message :



 this.state = { searchString: 'london', isLoading: false, message: '' };
      
      





render :



 <Text style={styles.description}>{this.state.message}</Text>
      
      





.



SearchPage _executeQuery() :



 fetch(query) .then(response => response.json()) .then(json => this._handleResponse(json.response)) .catch(error => this.setState({ isLoading: false, message: 'Something bad happened ' + error }));
      
      





fetch , Web API API XMLHttpRequest. promise , JSON-, _handleResponse ( ).



, SearchPage :



 _handleResponse(response) { this.setState({ isLoading: false , message: '' }); if (response.application_response_code.substr(0, 1) === '1') { console.log('Properties found: ' + response.listings.length); } else { this.setState({ message: 'Location not recognized; please try again.'}); } }
      
      





isLoading .



: Nestoria API . , 202 200 , . ?



, Cmd+R. 'london'. , 20 ( ). , 'narnia'. :







.







SearchResults.js :



 'use strict'; var React = require('react-native'); var { StyleSheet, Image, View, TouchableHighlight, ListView, Text, Component } = React;
      
      





, require , react-native .



:



 class SearchResults extends Component { constructor(props) { super(props); var dataSource = new ListView.DataSource( {rowHasChanged: (r1, r2) => r1.guid !== r2.guid}); this.state = { dataSource: dataSource.cloneWithRows(this.props.listings) }; } renderRow(rowData, sectionID, rowID) { return ( <TouchableHighlight underlayColor='#dddddd'> <View> <Text>{rowData.title}</Text> </View> </TouchableHighlight> ); } render() { return ( <ListView dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)}/> ); } }
      
      





– ListView , , UITableView . ListView ListView.DataSource , UI .



, , . ListView , . Nestoria API guid , .



:



 module.exports = SearchResults;
      
      





SearchPage.js , require React:



 var SearchResults = require('./SearchResults');
      
      





SearchResults SearchPage :



_handleResponse , console.log :



 this.props.navigator.push({ title: 'Results', component: SearchResults, passProps: {listings: response.listings} });
      
      





SearchResults API-. push- , 'Back', .



, , Cmd+R . :







- . , . .







React Native , .



SearchResults.js :



 var styles = StyleSheet.create({ thumb: { width: 80, height: 80, marginRight: 10 }, textContainer: { flex: 1 }, separator: { height: 1, backgroundColor: '#dddddd' }, price: { fontSize: 25, fontWeight: 'bold', color: '#48BBEC' }, title: { fontSize: 20, color: '#656565' }, rowContainer: { flexDirection: 'row', padding: 10 } });
      
      





.



renderRow() :



 renderRow(rowData, sectionID, rowID) { var price = rowData.price_formatted.split(' ')[0]; return ( <TouchableHighlight onPress={() => this.rowPressed(rowData.guid)} underlayColor='#dddddd'> <View> <View style={styles.rowContainer}> <Image style={styles.thumb} source={{ uri: rowData.img_url }} /> <View style={styles.textContainer}> <Text style={styles.price}>£{price}</Text> <Text style={styles.title} numberOfLines={1}>{rowData.title}</Text> </View> </View> <View style={styles.separator}/> </View> </TouchableHighlight> ); }
      
      





, '300,000 GBP' GBP. , , , , . ( Image ) URL ( rowData.img_url ), React Native , .



onPress TouchableHighlight . guid .



– , :



 rowPressed(propertyGuid) { var property = this.props.listings.filter(prop => prop.guid === propertyGuid)[0]; }
      
      





, . , , . .



, Cmd+R, :








 .



, .







PropertyView.js :



 'use strict'; var React = require('react-native'); var { StyleSheet, Image, View, Text, Component } = React;
      
      





, .



:



 var styles = StyleSheet.create({ container: { marginTop: 65 }, heading: { backgroundColor: '#F8F8F8', }, separator: { height: 1, backgroundColor: '#DDDDDD' }, image: { width: 400, height: 300 }, price: { fontSize: 25, fontWeight: 'bold', margin: 5, color: '#48BBEC' }, title: { fontSize: 20, margin: 5, color: '#656565' }, description: { fontSize: 18, margin: 5, color: '#656565' } });
      
      





:



 class PropertyView extends Component { render() { var property = this.props.property; var stats = property.bedroom_number + ' bed ' + property.property_type; if (property.bathroom_number) { stats += ', ' + property.bathroom_number + ' ' + (property.bathroom_number > 1 ? 'bathrooms' : 'bathroom'); } var price = property.price_formatted.split(' ')[0]; return ( <View style={styles.container}> <Image style={styles.image} source={{uri: property.img_url}} /> <View style={styles.heading}> <Text style={styles.price}>£{price}</Text> <Text style={styles.title}>{property.title}</Text> <View style={styles.separator}/> </View> <Text style={styles.description}>{stats}</Text> <Text style={styles.description}>{property.summary}</Text> </View> ); } }
      
      





, API . render() .



: .



:



 module.exports = PropertyView;
      
      





SearchResults.js require , React require :



 var PropertyView = require('./PropertyView');
      
      





rowPressed() , PropertyView :



 rowPressed(propertyGuid) { var property = this.props.listings.filter(prop => prop.guid === propertyGuid)[0]; this.props.navigator.push({ title: "Property", component: PropertyView, passProps: {property: property} }); }
      
      





: , Cmd+R. , :







, !



, .







Xcode Info.plist NSLocationWhenInUseUsageDescription :



 PropertyFinder would like to use your location to find nearby properties –
      
      





plist- :







, .



SearchPage.js, TouchableHighlight , 'Location', :



 onPress={this.onLocationPressed.bind(this)}
      
      





onLocationPressed ( ).



SearchPage :



 onLocationPressed() { navigator.geolocation.getCurrentPosition( location => { var search = location.coords.latitude + ',' + location.coords.longitude; this.setState({ searchString: search }); var query = urlForQueryAndPage('centre_point', search, 1); this._executeQuery(query); }, error => { this.setState({ message: 'There was a problem with obtaining your location: ' + error }); }); }
      
      





navigator.geolocation . Web API , , . React Native API, iOS.



. Nestoria. - , .



plist, , . , , Cmd+R. Xcode . .



, , Nestoria . Debug\Location\Custom Location 
 : , 55.02 -1.42 . , .



Location, .







: . , , , . . , React Native. - , , .



, , .



?



React Native. , .



-, , , JavaScript React. , , React Native, , JavaScript CSS.



, ? , Swift Objective-C? , , - .



, .



All Articles