泚ïŒããã¯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? , , - .
, .