Tải bản đầy đủ (.pdf) (432 trang)

Learning React Native: Building Mobile Applications with JavaScript

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (15.53 MB, 432 trang )

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1></div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2></div>
<span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

<b>LearningReactNative</b>



BuildingMobileApplicationswithJavaScript


</div>
<span class='text_page_counter'>(4)</span><div class='page_container' data-page=4></div>
<span class='text_page_counter'>(5)</span><div class='page_container' data-page=5>

<b>LearningReactNative</b>


byBonnieEisenman


Copyright©2016BonnieEisenman.Allrightsreserved.


PrintedintheUnitedStatesofAmerica.


PublishedbyO’ReillyMedia,Inc.,1005GravensteinHighwayNorth,Sebastopol,CA
95472.


O’Reillybooksmaybepurchasedforeducational,business,orsalespromotionaluse.
Onlineeditionsarealsoavailableformosttitles().Formore
information,contactourcorporate/institutionalsalesdepartment:800-998-9938or


<i></i>


Editor:MegFoley


ProductionEditor:NicholasAdams


Copyeditor:JasmineKwityn


Proofreader:ChristinaEdwards


Indexer:EllenTroutman-Zaig



InteriorDesigner:DavidFutato


CoverDesigner:RandyComer


Illustrator:RebeccaDemarest


</div>
<span class='text_page_counter'>(6)</span><div class='page_container' data-page=6>

<b>RevisionHistoryfortheFirstEdition</b>


2015-12-01:FirstRelease


Seeforreleasedetails.


<i>TheO’ReillylogoisaregisteredtrademarkofO’ReillyMedia,Inc.LearningReact</i>


<i>Native,thecoverimage,andrelatedtradedressaretrademarksofO’ReillyMedia,Inc.</i>


Whilethepublisherandtheauthorhaveusedgoodfaitheffortstoensurethatthe
informationandinstructionscontainedinthisworkareaccurate,thepublisherandthe
authordisclaimallresponsibilityforerrorsoromissions,includingwithoutlimitation
responsibilityfordamagesresultingfromtheuseoforrelianceonthiswork.Useofthe
informationandinstructionscontainedinthisworkisatyourownrisk.Ifanycode
samplesorothertechnologythisworkcontainsordescribesissubjecttoopensource
licensesortheintellectualpropertyrightsofothers,itisyourresponsibilitytoensurethat
yourusethereofcomplieswithsuchlicensesand/orrights.


978-1-491-92900-1


</div>
<span class='text_page_counter'>(7)</span><div class='page_container' data-page=7></div>
<span class='text_page_counter'>(8)</span><div class='page_container' data-page=8>

<b>Preface</b>



ThisbookisanintroductiontoReactNative,Facebook’sJavaScriptframeworkfor


buildingmobileapplications.UsingyourexistingknowledgeofJavaScriptandReact,
you’llbeabletobuildanddeployfullyfeaturedmobileapplicationsforbothiOSand
Androidthattrulyrendernatively.Justbecauseit’sJavaScriptdoesn’tmeanweshould
settleforless.ThereareplentyofadvantagestoworkingwithReactNativeover


traditionalmeansofmobiledevelopment,andwedon’tneedtosacrificethenativelook
andfeel.


We’llstartwiththebasics,andworkourwayuptodeployingafull-fledgedapplicationto
boththeiOSAppStoreandtheGooglePlayStore,with100%codereusebetweenthetwo
platforms.Inadditiontotheessentialsoftheframework,we’lldiscusshowtowork


beyondit,includinghowtomakeuseofthird-partylibrariesandevenhowtowriteyour
ownJavaorObjective-ClibrariestoextendReactNative.


</div>
<span class='text_page_counter'>(9)</span><div class='page_container' data-page=9>

<b>Prerequisites</b>



ThisbookisnotanintroductiontoReact,ingeneral.We’llassumethatyouhavesome
workingknowledgeofReact.Ifyou’rebrandnewtoReact,Isuggestreadingthrougha
tutorialortwobeforecomingbacktotaketheplungeintomobiledevelopment.


Specifically,youshouldbefamiliarwiththeroleofpropsandstate,thecomponent
lifecycle,andhowtocreateReactcomponents.


We’llalsobeusingsomeES6syntax,aswellasJSX.Ifyouaren’tfamiliarwiththese,
don’tworry;we’llcoverJSXinChapter2,andES6syntaxinAppendixA.Thesefeatures
areessentially1:1translationsoftheJavaScriptcodeyou’realreadyaccustomedto


writing.



</div>
<span class='text_page_counter'>(10)</span><div class='page_container' data-page=10>

<b>ConventionsUsedinThisBook</b>



Thefollowingtypographicalconventionsareusedinthisbook:


<i>Italic</i>


Indicatesnewterms,URLs,emailaddresses,filenames,andfileextensions.


<i>Constantwidth</i>


Usedforprogramlistings,aswellaswithinparagraphstorefertoprogramelements
suchasvariableorfunctionnames,databases,datatypes,environmentvariables,
statements,andkeywords.


<i><b>Constantwidthbold</b></i>


Showscommandsorothertextthatshouldbetypedliterallybytheuser.


<i>Constantwidthitalic</i>


Showstextthatshouldbereplacedwithuser-suppliedvaluesorbyvaluesdetermined
bycontext.


<b>TIP</b>


Thiselementsignifiesatiporsuggestion.


<b>NOTE</b>


Thiselementsignifiesageneralnote.



<b>WARNING</b>


</div>
<span class='text_page_counter'>(11)</span><div class='page_container' data-page=11>

<b>UsingCodeExamples</b>



Supplementalmaterial(codeexamples,exercises,etc.)isavailablefordownloadat:
<i> />


Thisbookisheretohelpyougetyourjobdone.Ingeneral,ifexamplecodeisoffered
withthisbook,youmayuseitinyourprogramsanddocumentation.Youdonotneedto
contactusforpermissionunlessyou’rereproducingasignificantportionofthecode.For
example,writingaprogramthatusesseveralchunksofcodefromthisbookdoesnot
requirepermission.SellingordistributingaCD-ROMofexamplesfromO’Reillybooks
doesrequirepermission.Answeringaquestionbycitingthisbookandquotingexample
codedoesnotrequirepermission.Incorporatingasignificantamountofexamplecode
fromthisbookintoyourproduct’sdocumentationdoesrequirepermission.


Weappreciate,butdonotrequire,attribution.Anattributionusuallyincludesthetitle,
<i>author,publisher,andISBN.Forexample:“LearningReactNativebyBonnieEisenman</i>
(O’Reilly).Copyright2016BonnieEisenman,978-1-491-92900-1.”


</div>
<span class='text_page_counter'>(12)</span><div class='page_container' data-page=12>

<b>Safari®BooksOnline</b>



<b>NOTE</b>



<i>SafariBooksOnlineisanon-demanddigitallibrarythatdeliversexpert</i>contentinboth
bookandvideoformfromtheworld’sleadingauthorsintechnologyandbusiness.


Technologyprofessionals,softwaredevelopers,webdesigners,andbusinessandcreative
professionalsuseSafariBooksOnlineastheirprimaryresourceforresearch,problem
solving,learning,andcertificationtraining.



SafariBooksOnlineoffersarangeofplansandpricingforenterprise,government,


education,andindividuals.


Membershaveaccesstothousandsofbooks,trainingvideos,andprepublication
manuscriptsinonefullysearchabledatabasefrompublisherslikeO’ReillyMedia,
PrenticeHallProfessional,Addison-WesleyProfessional,MicrosoftPress,Sams,Que,
PeachpitPress,FocalPress,CiscoPress,JohnWiley&Sons,Syngress,Morgan


Kaufmann,IBMRedbooks,Packt,AdobePress,FTPress,Apress,Manning,NewRiders,
McGraw-Hill,Jones&Bartlett,CourseTechnology,andhundredsmore.Formore


</div>
<span class='text_page_counter'>(13)</span><div class='page_container' data-page=13>

<b>HowtoContactUs</b>



Pleaseaddresscommentsandquestionsconcerningthisbooktothepublisher:


O’ReillyMedia,Inc.


1005GravensteinHighwayNorth


Sebastopol,CA95472


800-998-9938(intheUnitedStatesorCanada)


707-829-0515(internationalorlocal)


707-829-0104(fax)


Wehaveawebpageforthisbook,wherewelisterrata,examples,andanyadditional


information.Youcanaccessthispageat />


Tocommentorasktechnicalquestionsaboutthisbook,sendemailto
<i></i>


Formoreinformationaboutourbooks,courses,conferences,andnews,seeourwebsiteat
<i>.</i>


FindusonFacebook: />


FollowusonTwitter: />


</div>
<span class='text_page_counter'>(14)</span><div class='page_container' data-page=14>

<b>Resources</b>



It’sdangeroustogoalone!Well,notreally,butthatdoesn’tmeanyouhaveto.Hereare
someresourcesyoumayfindusefulasyouworkthroughthebook:


TheGitHubrepositoryforthisbookcontainsallofthecodesampleswe’llbe
discussing.Ifyougetstumped,orwantmorecontext,trylookingherefirst.


JointhemailinglistatLearningReactNative.comforfollow-uparticles,suggestions,
andhelpfulresources.


Theofficialdocumentationhasalotofgoodreferencematerial.


Additionally,theReactNativecommunityisausefulresource:


BrentVatne’sReactNativenewsletter


Thereact-nativetagonStackOverflow


</div>
<span class='text_page_counter'>(15)</span><div class='page_container' data-page=15>

<b>Acknowledgments</b>




Asistraditional:thisbookwouldnothavebeenpossiblewithoutthehelpandsupportof
manyothers.Thankyoutomyeditor,MegFoley,andtherestoftheO’Reillyteam,for
bringingthisprojectintotheworld.Thankyoualsotomytechnicalreviewers,foryour
timeandinsightfulfeedback:DavidBieber,JasonBrown,EricaPortnoy,andJonathan
Stark.IwouldalsoliketothanktheReactNativeteam,withoutwhosestellarworkthis
bookwouldnaturallybeimpossible.ThanksalsotoZacharyElliotforhishelpwiththe
ZebretoapplicationandAndroidingeneral.


</div>
<span class='text_page_counter'>(16)</span><div class='page_container' data-page=16></div>
<span class='text_page_counter'>(17)</span><div class='page_container' data-page=17>

<b>Chapter1.WhatIsReactNative?</b>



ReactNativeisaJavaScriptframeworkforwritingreal,nativelyrenderingmobile
applicationsforiOSandAndroid.It’sbasedonReact,Facebook’sJavaScriptlibraryfor
buildinguserinterfaces,butinsteadoftargetingthebrowser,ittargetsmobileplatforms.
Inotherwords:webdeveloperscannowwritemobileapplicationsthatlookandfeeltruly
“native,”allfromthecomfortofaJavaScriptlibrarythatwealreadyknowandlove.Plus,
becausemostofthecodeyouwritecanbesharedbetweenplatforms,ReactNativemakes
iteasytosimultaneouslydevelopforbothAndroidandiOS.


SimilartoReactfortheWeb,ReactNativeapplicationsarewrittenusingamixtureof
JavaScriptandXML-esquemarkup,knownasJSX.Then,underthehood,theReact
Native“bridge”invokesthenativerenderingAPIsinObjective-C(foriOS)orJava(for
<i>Android).Thus,yourapplicationwillrenderusingrealmobileUIcomponents,not</i>
webviews,andwilllookandfeellikeanyothermobileapplication.ReactNativealso
exposesJavaScriptinterfacesforplatformAPIs,soyourReactNativeappscanaccess
platformfeatureslikethephonecamera,ortheuser’slocation.


ReactNativecurrentlysupportsbothiOSandAndroid,andhasthepotentialtoexpandto
futureplatformsaswell.Inthisbook,we’llcoverbothiOSandAndroid.Thevast


</div>
<span class='text_page_counter'>(18)</span><div class='page_container' data-page=18>

<b>AdvantagesofReactNative</b>




ThefactthatReactNativeactuallyrendersusingitshostplatform’sstandardrendering
APIsenablesittostandoutfrommostexistingmethodsofcross-platformapplication
development,likeCordovaorIonic.Existingmethodsofwritingmobileapplications
usingcombinationsofJavaScript,HTML,andCSStypicallyrenderusingwebviews.
Whilethisapproachcanwork,italsocomeswithdrawbacks,especiallyaround


performance.Additionally,theydonotusuallyhaveaccesstothehostplatform’ssetof
nativeUIelements.WhentheseframeworksdotrytomimicnativeUIelements,the
resultsusually“feel”justalittleoff;reverse-engineeringallthefinedetailsofthingslike
animationstakesanenormousamountofeffort,andtheycanquicklybecomeoutofdate.


Incontrast,ReactNativeactuallytranslatesyourmarkuptoreal,nativeUIelements,
leveragingexistingmeansofrenderingviewsonwhateverplatformyouareworkingwith.
Additionally,ReactworksseparatelyfromthemainUIthread,soyourapplicationcan
maintainhighperformancewithoutsacrificingcapability.TheupdatecycleinReact
NativeisthesameasinReact:whenpropsorstatechange,ReactNativere-rendersthe
views.ThemajordifferencebetweenReactNativeandReactinthebrowseristhatReact
NativedoesthisbyleveragingtheUIlibrariesofitshostplatform,ratherthanusing
HTMLandCSSmarkup.


FordevelopersaccustomedtoworkingontheWebwithReact,thismeansyoucanwrite
mobileappswiththeperformanceandlookandfeelofanativeapplication,whileusing
familiartools.ReactNativealsorepresentsanimprovementovernormalmobile


</div>
<span class='text_page_counter'>(19)</span><div class='page_container' data-page=19>

<b>DeveloperExperience</b>



Ifyou’veeverdevelopedformobilebefore,youmightbesurprisedbyhoweasyReact
Nativeistoworkwith.TheReactNativeteamhasbakedstrongdevelopertoolsand
meaningfulerrormessagesintotheframework,soworkingwithrobusttoolsisanatural


partofyourdevelopmentexperience.


Forinstance,becauseReactNativeis“just”JavaScript,youdon’tneedtorebuildyour
applicationinordertoseeyourchangesreflected;instead,youcanhitCommand+Rto
refreshyourapplicationjustasyouwouldanyotherwebpage.Allofthoseminutesspent
waitingforyourapplicationtobuildcanreallyaddup,andincontrastReactNative’s
quickiterationcyclefeelslikeagodsend.


Additionally,ReactNativeletsyoutakeadvantageofintelligentdebuggingtoolsanderror
reporting.IfyouarecomfortablewithChromeorSafari’sdevelopertools(Figure1-1),
youwillbehappytoknowthatyoucanusethemformobiledevelopment,aswell.


</div>
<span class='text_page_counter'>(20)</span><div class='page_container' data-page=20>

<i>Figure1-1.UsingtheChromeDebugger</i>


Besidestheday-to-dayimprovementstoyourdevelopmentexperience,ReactNativealso
hasthepotentialtopositivelyimpactyourproductreleasecycle.Forinstance,Apple
permitsJavaScript-basedchangestoanapp’sbehaviortobeloadedovertheairwithno
additionalreviewcyclenecessary.


</div>
<span class='text_page_counter'>(21)</span><div class='page_container' data-page=21>

<b>CodeReuseandKnowledgeSharing</b>



WorkingwithReactNativecandramaticallyshrinktheresourcesrequiredtobuildmobile
applications.AnydeveloperwhoknowshowtowriteReactcodecannowtargettheWeb,
iOS,andAndroid,allwiththesameskillset.Byremovingtheneedto“silo”developers
basedontheirtargetplatform,ReactNativeletsyourteamiteratemorequickly,andshare
knowledgeandresourcesmoreeffectively.


</div>
<span class='text_page_counter'>(22)</span><div class='page_container' data-page=22>

<b>RisksandDrawbacks</b>



Aswithanything,usingReactNativeisnotwithoutitsdownsides,andwhetherornot


ReactNativeisagoodfitforyourteamreallydependsonyourindividualsituation.


ThelargestriskisprobablyReactNative’smaturity,astheprojectisstillrelativelyyoung.
iOSsupportwasreleasedinMarch2015,andAndroidsupportwasreleasedinSeptember
2015.Thedocumentationcertainlyhasroomforimprovement,andcontinuestoevolve.
SomefeaturesoniOSandAndroidstillaren’tsupported,andthecommunityisstill
discoveringbestpractices.Thegoodnewsisthatinthevastmajorityofcases,youcan
implementsupportformissingAPIsyourself,whichwe’llcoverinChapter7.


BecauseReactNativeintroducesanotherlayertoyourproject,itcanalsomakedebugging
hairier,especiallyattheintersectionofReactandthehostplatform.We’llcover


debuggingforReactNativeinmoredepthinChapter8,andtrytoaddresssomeofthe
mostcommonissues.


</div>
<span class='text_page_counter'>(23)</span><div class='page_container' data-page=23>

<b>Summary</b>



ReactNativeisanexcitingframeworkthatenableswebdeveloperstocreaterobustmobile
applicationsusingtheirexistingJavaScriptknowledge.Itoffersfastermobile


development,andmoreefficientcodesharingacrossiOS,Android,andtheWeb,without
sacrificingtheenduser’sexperienceorapplicationquality.Thetradeoffisthatit’snew,
andstillaworkinprogress.Ifyourteamcanhandletheuncertaintythatcomeswith
workingwithanewtechnology,andwantstodevelopmobileapplicationsformorethan
justoneplatform,youshouldbelookingatReactNative.


Inthenextchapter,we’llgooversomeofthemainwaysinwhichReactNativediffers
fromReactfortheWeb,andcoversomekeyconcepts.Ifyou’dliketoskipstraightto
developing,feelfreetojumptoChapter3,inwhichwe’llhandlesettingupour



</div>
<span class='text_page_counter'>(24)</span><div class='page_container' data-page=24></div>
<span class='text_page_counter'>(25)</span><div class='page_container' data-page=25>

<b>Chapter2.WorkingwithReactNative</b>



Inthischapter,we’llcoverthe“bridge,”andreviewhowReactNativeworksunderthe
hood.Then,we’lllookathowReactNativecomponentsdifferfromtheirweb


counterparts,andcoverwhatyou’llneedtoknowinordertocreateandstylecomponents
formobile.


<b>NOTE</b>


</div>
<span class='text_page_counter'>(26)</span><div class='page_container' data-page=26>

<b>HowDoesReactNativeWork?</b>



TheideaofwritingmobileapplicationsinJavaScriptfeelsalittleodd.Howisitpossible
touseReactinamobileenvironment?Inordertounderstandthetechnicalunderpinnings
ofReactNative,firstwe’llneedtorecalloneofReact’sfeatures,theVirtualDOM.


InReact,theVirtualDOMactsasalayerbetweenthedeveloper’sdescriptionofhow
thingsoughttolook,andtheworkdonetoactuallyrenderyourapplicationontothepage.
Torenderinteractiveuserinterfacesinabrowser,developersmusteditthebrowser’s
DOM,orDocumentObjectModel.Thisisanexpensivestep,andexcessivewritestothe
DOMhaveasignificantimpactonperformance.Ratherthandirectlyrenderchangeson
thepage,Reactcomputesthenecessarychangesbyusinganin-memoryversionofthe
DOM,andrerenderstheminimalamountnecessary.Figure2-1showshowthisworks.


<i>Figure2-1.PerformingcalculationsintheVirtualDOMlimitsrerenderingintheBrowserDOM</i>


InthecontextofReactontheWeb,mostdevelopersthinkoftheVirtualDOMprimarily
asaperformanceoptimization.TheVirtualDOMcertainlyhasperformancebenefits,but
itsrealpotentialliesinthepowerofitsabstraction.Placingacleanabstractionlayer
betweenthedeveloper’scodeandtheactualrenderingopensupalotofinteresting



possibilities.WhatifReactcouldrendertoatargetotherthanthebrowser’sDOM?After
<i>all,Reactalready“understands”whatyourapplicationissupposedtolooklike.</i>


</div>
<span class='text_page_counter'>(27)</span><div class='page_container' data-page=27>

components,orJavaAPIstorendertoAndroidcomponents.ThissetsReactNativeapart

fromothercross-platformappdevelopmentoptions,whichoftenenduprenderingweb-basedviews.


<i>Figure2-2.Reactcanrendertodifferenttargets</i>


Thisisallpossiblebecauseofthe“bridge,”whichprovidesReactwithaninterfaceinto
thehostplatform’snativeUIelements.Reactcomponentsreturnmarkupfromtheir
renderfunction,whichdescribeshowtheyshouldlook.WithReactfortheWeb,this
translatesdirectlytothebrowser’sDOM.ForReactNative,thismarkupistranslatedto
suitthehostplatform,soa<View>mightbecomeaniOS-specificUIView.


ReactNativecurrentlysupportsiOSandAndroid.Becauseoftheabstractionlayer


</div>
<span class='text_page_counter'>(28)</span><div class='page_container' data-page=28>

<b>RenderingLifecycle</b>



IfyouareaccustomedtoworkinginReact,theReactlifecycleshouldbefamiliartoyou.
WhenReactrunsinthebrowser,therenderlifecyclebeginsbymountingyourReact
components(Figure2-3).


<i>Figure2-3.MountingcomponentsinReact</i>


Afterthat,Reacthandlestherenderingandrerenderingofyourcomponentasnecessary
(Figure2-4).


<i>Figure2-4.RerenderingcomponentsinReact</i>



Fortherenderstage,thedeveloperreturnsHTMLmarkupfromaReactcomponent’s
rendermethod,whichReactthenrendersdirectlyintothepageasnecessary.


ForReactNative,thelifecycleisthesame,buttherenderingprocessisslightlydifferent,
becauseReactNativedependsonthebridge.Welookedatthebridgebrieflyearlierin


Figure2-2.ThebridgetranslatesJavaScriptcallsandinvokesthehostplatform’s


</div>
<span class='text_page_counter'>(29)</span><div class='page_container' data-page=29>

<b>CreatingComponentsinReactNative</b>



</div>
<span class='text_page_counter'>(30)</span><div class='page_container' data-page=30>

<b>WorkingwithViews</b>



WhenwritinginReactfortheWeb,yourendernormalHTMLelements(<div>,<p>,


<span>,<a>


,etc.).WithReactNative,alloftheseelementsarereplacedbyplatform-specificReactcomponents(seeTable2-1).Themostbasicisthecross-platform<View>,a
simpleandflexibleUIelementthatcanbethoughtofasanalogoustothe<div>.OniOS,
forinstance,the<View>componentrenderstoaUIView,whileonAndroiditrenderstoa
View.


<i>Table2-1.Basic</i>
<i>elementsforthe</i>
<i>Web,comparedwith</i>


<i>ReactNative</i>
<b>React</b> <b>ReactNative</b>


<div> <View>



<span> <Text>


<li>,<ul> <ListView>


<img> <Image>


Othercomponentsareplatform-specific.Forinstance,the<DatePickerIOS>component
(predictably)renderstheiOSstandarddatepicker.HereisanexcerptfromtheUIExplorer
sampleapp,demonstratinganiOSdatepicker.Theusageisstraightforward,asyouwould
expect:


<DatePickerIOS


date={this.state.date}
mode="date"


timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours*60}
/>


</div>
<span class='text_page_counter'>(31)</span><div class='page_container' data-page=31>

<i>Figure2-5.TheDatePickerIOSis,asthenamewouldsuggest,iOS-specific</i>


BecauseallofourUIelementsarenowReactcomponents,ratherthanbasicHTML
elementslikethe<div>,youwillneedtoexplicitlyimporteachcomponentyouwishto
use.Forinstance,weneededtoimportthe<DatePickerIOS>componentlikeso:


<b>var</b>React=require('react-native');
<b>var{</b>


DatePickerIOS



}=React;


TheUIExplorerapplication,whichisbundledintothestandardReactNativeexamples,
allowsyoutoviewallofthesupportedUIelements.Iencourageyoutoexaminethe
variouselementsincludedintheUIExplorerapp.Italsodemonstratesmanystyling
optionsandinteractions.


<b>TIP</b>


Platform-specificcomponentsandAPIshavespecialtagsinthedocumentation,andtypicallyusethe
platformnameasasuffix—forexample,<SwitchAndroid>and<SwitchIOS>.


Becausethesecomponentsvaryfromplatformtoplatform,howyoustructureyourReact
componentsbecomesevenmoreimportantwhenworkinginReactNative.InReactfor
theWeb,weoftenhaveamixofReactcomponents:somemanagelogicandtheirchild
components,whileothercomponentsrenderrawmarkup.Ifyouwanttoreusecodewhen
workinginReactNative,maintainingseparationbetweenthesetypesofcomponents
becomescritical.AReactcomponentthatrendersa<DatePickerIOS>elementobviously
cannotbereusedforAndroid.However,acomponentthatencapsulatestheassociated


</div>
<span class='text_page_counter'>(32)</span><div class='page_container' data-page=32>

platform.Youcanalsodesignateplatform-specificversionsofcomponents,ifyouwant,
<i>soyoucanhaveapicker.ios.jsandapicker.android.jsfile,forinstance.We’llcoverthisin</i>


</div>
<span class='text_page_counter'>(33)</span><div class='page_container' data-page=33>

<b>UsingJSX</b>


InReactNative,justasinReact,wewriteourviewsusingJSX,combiningmarkupand
theJavaScriptthatcontrolsitintoasinglefile.JSXmetwithstrongreactionswhenReact
firstdebuted.Formanywebdevelopers,theseparationoffilesbasedontechnologiesisa
given:youkeepyourCSS,HTML,andJavaScriptfilesseparate.Theideaofcombining
markup,controllogic,andevenstylingintoonelanguagecanbeconfusing.

<i>JSXprioritizestheseparationofconcernsovertheseparationoftechnologies.InReact</i>
Native,thisisevenmorestrictlyenforced.Inaworldwithoutthebrowser,itmakeseven
moresensetounifyourstyles,markup,andbehaviorinasinglefileforeachcomponent.
<i>Accordingly,your.jsfilesinReactNativeareinfactJSXfiles.Ifyouwereusingvanilla</i>
JavaScriptwhenworkingwithReactforweb,youwillwanttotransitiontoJSXsyntaxfor
yourworkinReactNative.

Ifyou’veneverseenJSXbefore,don’tworry:it’sprettysimple.Asanexample,apure-JavaScriptReactcomponentfortheWebmightlooksomethinglikethis:


<b>var</b>HelloMessage=React.createClass({
displayName:"HelloMessage",


render:functionrender(){
returnReact.createElement(
"div",


null,
"Hello",
this.props.name


);
}
});


React.render(React.createElement(HelloMessage,{name:"Bonnie"}),mountNode);
WecanrenderthismoresuccinctlybyusingJSX.Insteadofcalling


React.createElementandpassinginalistofHTMLattributes,weuseXML-like


markup:



<b>var</b>HelloMessage=React.createClass({
render:function(){


<i>//InsteadofcallingcreateElement,wereturnmarkup</i>


return<div>Hello{this.props.name}</div>;
}


});


<i>//WenolongerneedacreateElementcallhere</i>


React.render(<HelloMessagename="Bonnie"/>,mountNode);


BothofthesewillrenderthefollowingHTMLontothepage:


</div>
<span class='text_page_counter'>(34)</span><div class='page_container' data-page=34>

<b>StylingNativeComponents</b>


OntheWeb,westyleReactcomponentsusingCSS,justaswewouldanyotherHTML
element.Whetheryouloveitorhateit,CSSisanecessarypartoftheWeb.Reactusually
doesnotaffectthewaywewriteCSS.Itdoesmakeiteasiertouse(sane,useful)inline
styles,andtodynamicallybuildclassnamesbasedonpropsandstate,butotherwise
ReactismostlyagnosticabouthowwehandlestylesontheWeb.
Non-webplatformshaveawidearrayofapproachestolayoutandstyling.Whenwework
withReactNative,thankfully,weutilizeonestandardizedapproachtostyling.Partofthe
bridgebetweenReactandthehostplatformincludestheimplementationofaheavily
prunedsubsetofCSS.ThisnarrowimplementationofCSSreliesprimarilyonflexboxfor
layout,andfocusesonsimplicityratherthanimplementingthefullrangeofCSSrules.
UnliketheWeb,whereCSSsupportvariesacrossbrowsers,ReactNativeisableto
enforceconsistentsupportofstylerules.MuchlikethevariousUIelements,youcansee

manyexamplesofsupportedstylesintheUIExplorerapplication,whichisoneofthe


examplesthatshipswithReactNative.
ReactNativealsoinsistsontheuseofinlinestyles,whichexistasJavaScriptobjects.The
ReactteamhasadvocatedforthisapproachbeforeinReactforwebapplications.Ifyou
havepreviouslyexperimentedwithinlinestylesinReact,thesyntaxwilllookfamiliarto
you:
<i>//Defineastyle…</i>


<b>var</b>style={


backgroundColor:'white',
fontSize:'16px'


};


<i>//...andthenapplyit.</i>


<b>var</b>tv=(


<Textstyle={style}>
AstyledText


</Text>);


ReactNativealsoprovidesuswithsomeutilitiesforcreatingandextendingstyleobjects
thatmakedealingwithinlinestylesamoremanageableprocess.Wewillexplorethose
later,inChapter5.


</div>
<span class='text_page_counter'>(35)</span><div class='page_container' data-page=35>

<b>HostPlatformAPIs</b>



PerhapsthebiggestdifferencebetweenReactfortheWebandReactNativeisthewaywe
thinkabouthostplatformAPIs.OntheWeb,theissueathandisoftenfragmentedand
inconsistentadoptionofstandards;still,mostbrowserssupportacommoncoreofshared
features.WithReactNative,however,platform-specificAPIsplayamuchlargerrolein
creatinganexcellent,natural-feelinguserexperience.Therearealsomanymoreoptionsto
consider.MobileAPIsincludeeverythingfromdatastorage,tolocationservices,to
accessinghardwaresuchasthecamera.AsReactNativeexpandstootherplatforms,we
canexpecttoseeothersortsofAPIs,too;whatwouldtheinterfacelooklikebetween
ReactNativeandavirtualrealityheadset,forinstance?
Bydefault,ReactNativeforiOSandAndroidincludessupportformanyofthecommonly
usedfeatures,andReactNativecansupportanyasynchronousnativeAPI.Wewilltakea
lookatmanyofthemthroughoutthisbook.ReactNativemakesitstraightforwardand
simpletomakeuseofhostplatformAPIs,soyoucanexperimentfreely.Besuretothink
aboutwhatfeels“right”foryourtargetplatform,anddesignwithnaturalinteractionsin
mind.
Inevitably,theReactNativebridgewillnotexposeallhostplatformfunctionality.Ifyou
findyourselfinneedofanunsupportedfeature,youhavetheoptionofaddingittoReact
Nativeyourself.Alternatively,chancesaregoodthatsomeoneelsehasdonesoalready,so
besuretocheckinwiththecommunitytoseewhetherornotsupportwillbeforthcoming.
We’llcoverthisinChapter7.


</div>
<span class='text_page_counter'>(36)</span><div class='page_container' data-page=36>

<b>Summary</b>



</div>
<span class='text_page_counter'>(37)</span><div class='page_container' data-page=37></div>
<span class='text_page_counter'>(38)</span><div class='page_container' data-page=38>

<b>Chapter3.BuildingYourFirst</b>


<b>Application</b>



</div>
<span class='text_page_counter'>(39)</span><div class='page_container' data-page=39>

<b>SettingUpYourEnvironment</b>



Settingupyourdevelopmentenvironmentwillenableyoutofollowalongwiththe
examplesinthebook,andwillletyouwriteyourownapplications!



InstructionsforinstallingReactNativecanbefoundintheofficialReactNative


documentation.Theofficialsitewillbeyourmostup-to-datereferencepointforspecific
installationsteps,butwe’llwalkthroughthemhereaswell.


YouwillneedtouseHomebrew,acommonpackagemanagerforOSX,inordertoinstall
ReactNative’sdependencies.Throughoutthisbook,wewillassumethatyouare


developingonOSX,whichallowsyoutowritebothiOSandAndroidapplications.


OnceyouhaveHomebrewinstalled,runthefollowingfromthecommandline:


<b>brewinstallnode</b>
<b>brewinstallwatchman</b>
<b>brewinstallflow</b>


TheReactNativepackagerusesbothnodeandwatchman,soifthepackagergivesyou
troubleinthefutureit’sworthupdatingthesedependencies.flow
isFacebook’stype-checkinglibrary,andisalsousedbyReactNative.(Ifyouwanttoenabletype-checkingin
yourReactNativeprojects,youcanuseflow!)


Ifyouencounterdifficulties,youmayneedtoupdatebrewandupgradeanypackages
(notethatthesecommandsmaytakealittlewhiletorun):


<b>brewupdate</b>
<b>brewupgrade</b>


</div>
<span class='text_page_counter'>(40)</span><div class='page_container' data-page=40>

<b>InstallingReactNative</b>




Nowthatyouhavenodeinstalled,youcanusenpm(theNodePackageManager)toinstall
theReactNativecommand-linetools:


<b>npminstall-greact-native-cli</b>


ThisinstallstheReactNativecommand-linetoolsgloballyonyoursystem.Afterthisis
done,congrats;ReactNativeisinstalled!


</div>
<span class='text_page_counter'>(41)</span><div class='page_container' data-page=41>

<b>iOSDependencies</b>



InordertodevelopandreleaseappsforiOS,youwillneedtoacquireaniOSdeveloper’s
account.Theaccountisfree,andissufficientfordevelopment.Fordeployingapplications
totheiOSAppStore,you’lleventuallyneedalicense,whichispricedat$99/year.


Ifyouhaven’tdonesoalready,you’llwanttodownloadandinstallXcode,whichincludes
theXcodeIDE,theiOSsimulators,andtheiOSSDK.YoucandownloadXcodefromthe
AppStoreorfromtheXcodewebsite.


</div>
<span class='text_page_counter'>(42)</span><div class='page_container' data-page=42>

<b>AndroidDependencies</b>



Androidsetupisamultistepprocess.Youshouldchecktheofficialdocumentationforthe
mostup-to-dateinstructions.Notethattheseinstructionsassumeyoudon’talreadyhave
yourenvironmentsetupforAndroiddevelopment.Ingeneralterms,therearethreemain
phases:installingtheSDKs,installingthesimulatortools,andcreatingsimulatorsforuse.


First,you’llneedtoinstalltheJDK(JavaDevelopmentKit)andAndroidSDKs:


1. InstallthelatestJDK.


2. InstalltheAndroidSDK,usingbrewinstallandroid-sdk.



3. ExportyourANDROID_HOME<i>variableappropriatelyinyourshellconfigfile(~/.bashrc,</i>


<i>~/.zshrc,orwhicheveryourshelluses):</i>


exportANDROID_HOME=/usr/local/opt/android-sdk


ThisenvironmentvariableisusedformanyAndroid-relateddevelopmenttasks;makesure
tosourceyourshellconfigafteraddingit.


</div>
<span class='text_page_counter'>(43)</span><div class='page_container' data-page=43>

<i>Figure3-1.TheAndroidSDKManagerallowsyoutochoosewhichpackagestoinstall</i>


WaitfortheSDKManagertoupdateanddownloadthepackagelisting.Somepackages
willalreadybecheckedbydefault.Alsomakesuretochecktheboxesfor:


AndroidSDKBuild-toolsversion23.0.1


Android6.0(API23)


AndroidSupportRepository


Then,clickInstallPackagesandacceptanyapplicablelicenses.It’lltakealittlewhilefor
everythingtoinstall.


Next,you’llwanttoinstallthesimulatorandrelatedtools.


StartanewshellandrunandroidagaintolaunchtheAndroidSDKManager.We’re
goingtoinstallafewmorepackages:


</div>
<span class='text_page_counter'>(44)</span><div class='page_container' data-page=44>

Intelx86EmulatorAccelerator(HAXMinstaller)



Onceagain,clickInstallPackagesandacceptanyapplicablelicenses.


ThesepackagesgiveustheabilitytocreateAndroidVirtualDevices(AVDs),or


emulators,butwedon’tactuallyhaveanyemulatorscreatedyet.Let’scorrectthat.Launch
theAVDManager(showninFigure3-2)byrunning:


<b>androidavd</b>


<i>Figure3-2.TheAVDmanagerletsyoucreateandlaunchemulators</i>


</div>
<span class='text_page_counter'>(45)</span><div class='page_container' data-page=45>

<i>Figure3-3.Youcancreatewhicheveremulatorsyoulike(inthisexample,I’vecreatedaGalaxyNexusemulator)</i>


<i>Figure3-4.BesuretocheckUseHostGPU—otherwiseyouremulatorwillbeveryslow!</i>


</div>
<span class='text_page_counter'>(46)</span><div class='page_container' data-page=46>

<b>CreatingaNewApplication</b>



YoucanusetheReactNativecommand-linetoolstocreateanewapplication.Thiswill
generateafreshprojectwithalloftheReactNative,iOS,andAndroidboilerplateforyou:


<b>react-nativeinitFirstProject</b>


TheresultingdirectoryshouldhavethestructureshowninFigure3-5.


<i>Figure3-5.Filestructureinthedefaultproject</i>


<i>Theios/andandroid/directoriescontainboilerplaterelevanttothoseplatforms.Your</i>
<i>Reactcodeislocatedintheindex.ios.jsandandroid.ios.jsfiles,whicharetherespective</i>
entrypointsforyourReactapplication.Dependenciesinstalledvianpmcan,asusual,be


<i>foundinthenode_modules/folder.</i>


</div>
<span class='text_page_counter'>(47)</span><div class='page_container' data-page=47>

<b>RunningaReactNativeApplicationforiOS</b>



Forstarters,we’lltryrunningtheiOSversionofourReactNativeapplication,bothinthe
simulatorandonaphysicaldevice.


<i>OpentheFirstProject.xcodeprojfile,locatedintheios/directory,inXcode.Inthetopleft,</i>
you’llnoticeaRunbutton,asshowninFigure3-6.Pressingthiswillbuildandrunyour
application.YoucanalsochangethedeploytargetheretoadifferentiOSsimulator.


<i>Figure3-6.TheRunbutton,withdeploytargetselector</i>


WhenyoupressRun,theReactpackagershouldautomaticallylaunchinanewterminal
window.Ifitfailstolaunch,orprintsanerror,tryrunningnpminstallandnpmstart
<i>fromtheFirstProject/directory.</i>


ItshouldlooklikethescreenshotshowninFigure3-7.


<i>Figure3-7.TheReactpackager</i>


</div>
<span class='text_page_counter'>(48)</span><div class='page_container' data-page=48></div>
<span class='text_page_counter'>(49)</span><div class='page_container' data-page=49>

<i>Figure3-8.Screenshotofthedefaultapp</i>


</div>
<span class='text_page_counter'>(50)</span><div class='page_container' data-page=50>

<b>UploadingtoYouriOSDevice</b>



TouploadyourReactNativeapplicationtoaphysicaliOSdevice,youwillneedaniOS
developeraccountwithApple.Youwillthenneedtogenerateacertificateandregister
yourdevice.AfterregisteringwithApple,openXcode’spreferencesandaddyour
account,asshowninFigure3-9.



<i>Figure3-9.AddyouraccountinXcode’sPreferencespane</i>


</div>
<span class='text_page_counter'>(51)</span><div class='page_container' data-page=51>

<i>Figure3-10.Screenshotofthedefaultapp</i>


Havingobtainedacertificate,you’renearlydone.ThefinalstepistologontoApple
Developerandregisteryourdevice(seeFigure3-11).


<i>Figure3-11.RegisteringyourdeviceintheiOSdevelopermembercenter</i>


Obtainingyourdevice’sUDIDissimple.OpeniTunes,andselectyourdevice.Then,click
ontheserialnumber;itshouldnowdisplaytheUDIDinstead,andtheUDIDwillbe


copiedovertoyourclipboard.


OnceyouhaveregisteredyourdevicewithApple,itshouldappearinyourlistof
approveddevices.


Thisregistrationprocesscanalsobeusedlateron,ifyouwishtodistributeanearly
releasetoothertestdevices.Forindividualdevelopers,Applegivesyouanallotmentof
100devicesperyearthroughthedeveloperprogram.


Lastly,weneedtomakeaquickchangetoourcodebeforewecandeploy.Youwillneed
<i>toalteryourAppDelegate.mfiletoincludeyourMac’sIPaddressinsteadoflocalhost.If</i>
youdonotknowhowtofindyourcomputer’sIPaddress,youcanrunifconfigandthen
usetheinetvalueunderen0.


Forexample,ifyourIPaddresswas10.10.12.345,youshouldeditthejsCodeLocationto
looklikethis:


</div>
<span class='text_page_counter'>(52)</span><div class='page_container' data-page=52>

[NSURLURLWithString:@"http://10.10.12.345:8081/index.ios.bundle"];



Phew!Withallofthatoutoftheway,wecanselectaphysicaldeviceasthedeploytarget
inXcode(seeFigure3-12).


<i>Figure3-12.SelectyouriOSdeviceasthedeploytarget</i>


</div>
<span class='text_page_counter'>(53)</span><div class='page_container' data-page=53>

<b>RunningaReactNativeApplicationforAndroid</b>



TorunaReactNativeapplicationforAndroid,you’llneedtodotwothings:startthe
emulator,andthenrunyourapplication.


Earlier,inFigure3-2,wesawthatwecanlaunchtheAVDManagerbyrunning:


<b>androidavd</b>


SelecttheemulatoryouwouldliketorunandthenclicktheStart…button


Alternatively,youcanlaunchyouremulatorsfromthecommandline.Toviewavailable
emulators,type:


<b>emulator-list-avds</b>


Thenlaunchthembyname,prefixedbythe@symbol.Forinstance,IhaveanAVDnamed
“galaxy,”soIcanrunthefollowing:


<b>emulator@galaxy</b>


Regardlessofhowyouchosetostartyouremulator,onceit’srunning,launchyourReact
Nativeapplicationbyrunningthefollowingfromyourproject’srootdirectory:



</div>
<span class='text_page_counter'>(54)</span><div class='page_container' data-page=54>

<b>Recap:CreatingandRunningProjects</b>



Wecoveredalotofgroundhere!BecauseweneededtoinstalldependenciesforReact
Native,iOS,andAndroiddevelopment,thatmighthavefeltlikealotofwork.


</div>
<span class='text_page_counter'>(55)</span><div class='page_container' data-page=55>

<b>ExploringtheSampleCode</b>



</div>
<span class='text_page_counter'>(56)</span><div class='page_container' data-page=56>

<b>AttachingaComponenttotheView</b>


WhenaReactNativeapplicationlaunches,howdoesaReactcomponentgetboundtothe
view?Whatdetermineswhichcomponentisrendered?
Thisanswerisplatform-specific.We’llstartbylookingattheiOSversionofourproject.
<i>WecanfindtheanswerinsideofAppDelegate.m.Notice,inparticular,thelinesshownin</i>
Example3-1.
<i>Example3-1.Declaringtherootviewinios/AppDelegate.m</i>


RCTRootView*rootView=


[[RCTRootViewalloc]initWithBundleURL:jsCodeLocation


moduleName:@"FirstProject"


launchOptions:launchOptions];


TheReactNativelibraryprefixesallofitsclasseswithRCT,meaningthatRCTRootViewis
aReactNativeclass.Inthiscase,theRCTRootViewrepresentstherootReactview.The
<i>remainderoftheboilerplatecodeinAppDelegate.mhandlesattachingthisviewtoa</i>
UIViewControllerandrenderingtheviewtothescreen.Thesestepsareanalogousto


mountingaReactcomponenttoaDOMnodewithacalltoReact.render.



<i>Fornow,theAppDelegate.mfilecontainstwothingsthatyououghttoknowhowto</i>
modify.


ThefirstisthejsCodeLocationline,whichweeditedearlierinordertodeploytoa


physicaldevice.Asthecommentsinthegeneratedfileexplain,thefirstoptionisusedfor
development,whilethesecondoptionisusedfordeployingwithaprebundledfileondisk.
Fornow,wewillleavethefirstoptionuncommented.Later,oncewepreparetodeploy
applicationstotheAppStore,wewilldiscussthesetwoapproachesinmoredetail.


You’llalsoneedtomodifythemoduleName,whichispassedtotheRCTRootViewand
determineswhichcomponentwillbemountedintheview.Thisiswhereyoucanchoose
whichcomponentshouldberenderedbyyourapplication.


InordertousetheFirstProjectcomponenthere,youneedtoregisteraReactcomponent
<i>withthesamename.Ifyouopenupindex.ios.js,you’llseethatthisisaccomplishedonthe</i>
lastline(Example3-2).


<i>Example3-2.Registeringthetop-levelcomponent</i>


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


<i>ThisexposestheFirstProjectcomponentsothatwecanuseitinAppDelegate.m.Forthe</i>
mostpart,youwillnotneedtomodifythisboilerplate,butit’sgoodtoknowthatit’sthere.


<i>WhataboutonAndroid?Thestoryisprettysimilar.IfyoulookatMainActivity.java,</i>
you’llnoticethelineshowninExample3-3.


<i>Example3-3.ReactentrypointforAndroidisinMainActivity.java</i>



mReactRootView.startReactApplication(mReactInstanceManager,"FirstProject",null);


</div>
<span class='text_page_counter'>(57)</span><div class='page_container' data-page=57></div>
<span class='text_page_counter'>(58)</span><div class='page_container' data-page=58>

<b>ImportsinReactNative</b>



<i>Let’stakeacloserlookattheindex.ios.jsfile.Asyoucanseein</i>Example3-4,therequire
statementsusedareabitdifferentthannormal.


<i>Example3-4.requirestatementsinReactNative,andimportingUIelements</i>


varReact=require('react-native');


var{


AppRegistry,
StyleSheet,
Text,
View,
}=React;


There’ssomeinterestingsyntaxgoingonhere.Reactisrequiredasusual,butwhatis
happeningonthenextline?


OnequirkofworkingwithReactNativeisthatyouneedtoexplicitlyrequireevery
Native-providedmoduleyouworkwith.Thingslike<div>don’tsimplyexist;instead,
youneedtoexplicitlyimportcomponentssuchas<View>and<Text>.Libraryfunctions
suchasStylesheetandAppRegistryarealsoexplicitlyimportedusingthissyntax.Once
westartbuildingourownapplications,wewillexploretheotherReactNativefunctions
thatyoumayneedtoimport.


</div>
<span class='text_page_counter'>(59)</span><div class='page_container' data-page=59>

<b>TheFirstProjectComponent</b>




Let’stakealookatthe<FirstProject>component(Example3-5),whichisduplicated
<i>betweenindex.ios.jsandindex.android.js(inotherwords,youcanexamineeither,as</i>
they’reidentical).


Thisshouldalllookcomfortablyfamiliar,because<FirstProject>iswrittenjustlikean
ordinaryReactcomponent.Themaindifferenceisitsuseof<Text>and<View>


componentsinsteadof<div>and<span>,andtheuseofstyleobjects.


<i>Example3-5.FirstProjectcomponent,withstyles</i>


<b>var</b>FirstProject=React.createClass({
render:function(){


return(


<Viewstyle={styles.container}>
<Textstyle={styles.welcome}>
WelcometoReactNative!
</Text>


<Textstyle={styles.instructions}>
Togetstarted,editindex.ios.js


</Text>


<Textstyle={styles.instructions}>
PressCmd+Rtoreload,{'\n'}
Cmd+Dorshakefordevmenu



</Text>
</View>
);


}
});


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


justifyContent:'center',
alignItems:'center',
backgroundColor:'#F5FCFF',
},


welcome:{
fontSize:20,


textAlign:'center',
margin:10,


},


instructions:{


textAlign:'center',
color:'#333333',


marginBottom:5,
},


});


AsImentionedearlier,allstylinginReactNativeisdonewithstyleobjectsratherthan
stylesheets.ThestandardmethodofdoingthisisbyutilizingtheStyleSheetlibrary.You
canseehowthestyleobjectsaredefinedtowardthebottomofthefile.Notethatonly
<Text>componentscantaketext-specificstyleslikefontSize,andthatalllayoutlogicis


handledbyflexbox.Wewilldiscusshowtobuildlayoutswithflexboxatgreaterlength
lateroninChapter5.


Thesampleapplicationisagooddemonstrationofthebasicfunctionsyouwillneedto
createReactNativeapplications.ItmountsaReactcomponentforrendering,and


</div>
<span class='text_page_counter'>(60)</span><div class='page_container' data-page=60></div>
<span class='text_page_counter'>(61)</span><div class='page_container' data-page=61>

<b>BuildingaWeatherApp</b>



Wewillbebuildingoffofthesampleapplicationtocreateaweatherapp(youcancreatea
newoneforthisexamplewithreact-nativeinitWeatherProject).Thiswillgiveusa
chancetoexplorehowtoutilizeandcombinestylesheets,flexbox,network


communication,userinput,andimagesintoausefulappwecanthendeploytoan
AndroidoriOSdevice.


Thissectionmayfeellikeabitofablur,aswe’llbefocusingonanoverviewofthese
featuresratherthandeepexplanationsofthem.TheWeatherAppwillserveasauseful
referenceinfuturesectionsaswediscussthesefeaturesinmoredetail.Don’tworryifit
feelslikewe’removingquickly!



</div>
<span class='text_page_counter'>(62)</span><div class='page_container' data-page=62></div>
<span class='text_page_counter'>(63)</span><div class='page_container' data-page=63>

<i>Figure3-13.Thefinishedweatherapp</i>


Thefirstthingwe’lldoisreplacethedefaultcode.Movetheinitialcomponentoutintoits
<i>ownfile,WeatherProject.js,andreplacethecontentsofindex.ios.jsandindex.android.js.</i>


<i>Example3-6.Simplifiedcontentsofindex.ios.jsandindex.android.js(theyshouldbe</i>
<i>identical)</i>


<b>var</b>React=require('react-native');


<b>var{</b>AppRegistry}=React;


<b>var</b>WeatherProject=require('./WeatherProject');


</div>
<span class='text_page_counter'>(64)</span><div class='page_container' data-page=64>

<b>HandlingUserInput</b>



Wewanttheusertobeabletoinputazipcodeandgettheforecastforthatarea,sowe
needtoaddatextfieldforuserinput.Wecanstartbyaddingzipcodeinformationtoour
component’sinitialstate(seeExample3-7).


<i>Example3-7.Addthistoyourcomponent,beforetherenderfunction</i>


getInitialState:function(){
return{


zip:''


};
}



RememberthatgetInitialStateishowwesetuptheinitialstatevaluesforReact
components.IfyouneedareviewoftheReactcomponentlifecycle,seetheReactdocs.


Then,weshouldalsochangeoneofthe<Text>componentstodisplaythis.state.zip:


<Textstyle={styles.welcome}>
Youinput{this.state.zip}.
</Text>


Withthatoutoftheway,let’sadda<TextInput>component(thisisabasiccomponent
thatallowstheusertoentertext):


<TextInput


style={styles.input}


onSubmitEditing={this._handleTextChange}/>


The<TextInput>componentisdocumentedontheReactNativesite,alongwithits
properties.Youcanalsopassthe<TextInput>additionalcallbacksinordertolistento
otherevents,suchasonChangeoronFocus,butwedonotneedthematthemoment.
Notethatwe’veaddedasimplestyletothe<TextInput>.Addtheinputstyletoyour
stylesheet:
varstyles=StyleSheet.create({
...
input:{
fontSize:20,
borderWidth:2,
height:40
}


...
});


ThecallbackwepassedastheonSubmitEditingproplookslikethis,andshouldbeadded
asafunctiononthecomponent:


_handleTextChange(event){


console.log(event.nativeEvent.text);


this.setState({zip:event.nativeEvent.text})
}


</div>
<span class='text_page_counter'>(65)</span><div class='page_container' data-page=65>

yousodesire.


Youwillalsoneedtoupdateyourimportstatements:


<b>var</b>React=require('react-native');
<b>var{</b>


...
TextInput


...
}=React;


Now,tryrunningyourapplicationusingtheiOSsimulator.Itwon’tbepretty,butyou
shouldbeabletosuccessfullysubmitazipcodeandhaveitbereflectedinthe<Text>
component.
Ifwewanted,wecouldaddsomesimpleinputvalidationheretoensurethattheusertyped


inafive-digitnumber,butwewillskipthatfornow.
Example3-8<i>showsthefullcodefortheWeatherProject.jscomponent.</i>
<i>Example3-8.WeatherProject.js:thisversionsimplyacceptsandrecordsuserinput</i>


<b>var</b>React=require('react-native');
<b>var{</b>
StyleSheet,
Text,
View,
TextInput,
Image


}=React;


<b>var</b>WeatherProject=React.createClass({


<i>//Ifyouwanttohaveadefaultzipcode,youcouldaddonehere</i>


getInitialState(){
return({


zip:''


});
},


<i>//We'llpassthiscallbacktothe<TextInput></i>


_handleTextChange(event){



<i>//logstatementsareviewableinXcode,</i>


<i>//ortheChromedebugtools</i>


console.log(event.nativeEvent.text);
this.setState({


zip:event.nativeEvent.text


});
},


render(){
return(


<Viewstyle={styles.container}>
<Textstyle={styles.welcome}>
Youinput{this.state.zip}.
</Text>


<TextInput


style={styles.input}


onSubmitEditing={this._handleTextChange}/>
</View>


);
}
});



<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


</div>
<span class='text_page_counter'>(66)</span><div class='page_container' data-page=66>

backgroundColor:'#F5FCFF',
},


welcome:{
fontSize:20,


textAlign:'center',
margin:10,


},
input:{


fontSize:20,
borderWidth:2,
height:40


}
});


</div>
<span class='text_page_counter'>(67)</span><div class='page_container' data-page=67>

<b>DisplayingData</b>



Nowlet’sworkondisplayingtheforecastforthatzipcode.Wewillstartbyaddingsome
mockdatatogetInitialStateinWeatherProject.js:



getInitialState(){
return{


zip:'',
forecast:{
main:'Clouds',


description:'fewclouds',
temp:45.7


}
}
}


Forsanity’ssake,let’salsopulltheforecastrenderingintoitsowncomponent.Makea
<i>newfilecalledForecast.js(see</i>Example3-9).


<i>Example3-9.ForecastcomponentinForecast.js</i>


<b>var</b>React=require('react-native');
<b>var{</b>


StyleSheet,
Text,
View


}=React;


<b>var</b>Forecast=React.createClass({
render:function(){



return(
<View>


<Textstyle={styles.bigText}>
{this.props.main}


</Text>


<Textstyle={styles.mainText}>


Currentconditions:{this.props.description}
</Text>


<Textstyle={styles.bigText}>
{this.props.temp}°F


</Text>


</View>


);
}
});


<b>var</b>styles=StyleSheet.create({
bigText:{


flex:2,
fontSize:20,



textAlign:'center',
margin:10,


color:'#FFFFFF'


},


mainText:{
flex:1,
fontSize:16,


textAlign:'center',
color:'#FFFFFF'


}
})


module.exports=Forecast;


The<Forecast>componentjustrenderssome<Text>basedonitsprops.We’vealso
includedsomesimplestylesatthebottomofthefile,tocontrolthingsliketextcolor.


</div>
<span class='text_page_counter'>(68)</span><div class='page_container' data-page=68>

itpropsbasedonthethis.state.forecast(seeExample3-10).We’lladdressissueswith
layoutandstylinglater.Youcanseehowthe<Forecast>componentappearsinthe


resultingapplicationinFigure3-14.


<i>Example3-10.WeatherProject.jsshouldbeupdatedwithnewstateandtheForecast</i>
<i>component</i>



<b>var</b>React=require('react-native');
<b>var{</b>
StyleSheet,
Text,
View,
TextInput,
Image


}=React;


<b>var</b>Forecast=require('./Forecast');
<b>var</b>WeatherProject=React.createClass({
getInitialState(){


return{
zip:'',
forecast:{
main:'Clouds',


description:'fewclouds',
temp:45.7


}
}
},


_handleTextChange(event){


console.log(event.nativeEvent.text);


this.setState({


zip:event.nativeEvent.text


});
},


render(){
return(


<Viewstyle={styles.container}>
<Textstyle={styles.welcome}>
Youinput{this.state.zip}.
</Text>


<Forecast


main={this.state.forecast.main}


description={this.state.forecast.description}
temp={this.state.forecast.temp}/>


<TextInput


style={styles.input}
returnKeyType='go'


onSubmitEditing={this._handleTextChange}/>
</View>



);
}
});


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


justifyContent:'center',
alignItems:'center',
backgroundColor:'#4D4D4D',
},


welcome:{
fontSize:20,


textAlign:'center',
margin:10,


},
input:{


fontSize:20,
borderWidth:2,
height:40


</div>
<span class='text_page_counter'>(69)</span><div class='page_container' data-page=69></div>
<span class='text_page_counter'>(70)</span><div class='page_container' data-page=70></div>
<span class='text_page_counter'>(71)</span><div class='page_container' data-page=71></div>
<span class='text_page_counter'>(72)</span><div class='page_container' data-page=72>

<b>AddingaBackgroundImage</b>



</div>
<span class='text_page_counter'>(73)</span><div class='page_container' data-page=73></div>
<span class='text_page_counter'>(74)</span><div class='page_container' data-page=74>

<b>ASSETINCLUSIONISPLATFORM-SPECIFIC</b>



AndroidandiOShavedifferentrequirementsforaddingassetstoyourprojects.We’llcoverbothhere.


Assetssuchasimagesneedtobeaddedtoyourprojectbasedonwhichplatformyou’re
buildingfor.We’llstartwithXcode.


<i>SelecttheImages.xcassets/folder,andthenselecttheNewImageSetoption,asshownin</i>


Figure3-15.Then,youcandraganddropanimageintotheset.Figure3-16showsthe
resultingImageSet.Makesuretheimageset’snamematchesthefilename,otherwise
ReactNativewillhavedifficultyimportingit.


<i>Figure3-15.Addanewimageset</i>


<i>Figure3-16.Dragyourimagefilesintotheimagesettoaddthem</i>


The@2xand@3xdecoratorsindicateanimagewitharesolutionoftwiceandthricethe
baseresolution,respectively.BecausetheWeatherAppisdesignatedasauniversal


application(meaningonethatcanrunoniPhoneoriPad),Xcodegivesustheoptionof
uploadingimagesatthevariousappropriateresolutions.


ForAndroid,wehavetoaddourfilesasbitmapdrawableresourcestotheappropriate
<i>foldersinWeatherProject/android/app/src/main/res.You’llwanttocopythe.pngfileinto</i>
thefollowingresolution-specificdirectories(seeFigure3-17):


</div>
<span class='text_page_counter'>(75)</span><div class='page_container' data-page=75>

<i>Figure3-17.AddingimagefilestoAndroid</i>
Afterthat,theimagewillbeavailabletoyourAndroidapplication.
Ifthisworkflowfeelssuboptimal,that’sbecauseitis.Itwillprobablychangeinfuture
versionsofReactNative.


NowthattheimagefileshavebeenimportedintobothourAndroidandiOSprojects,let’s
hopbacktoourReactcode.Toaddabackgroundimage,wedon’tsetabackground


propertyona<div>likewecandoontheWeb.Instead,weusean<Image>componentas
acontainer:


<Imagesource={require('image!flowers')}
resizeMode='cover'


style={styles.backdrop}>
<i>//Yourcontenthere</i>


</Image>


The<Image>componentexpectsasourceprop,whichwegetbyusingrequire.Thecall
torequire(image!flowers)<i>willcauseReactNativetosearchforafilenamedflowers.</i>


Don’tforgettostyleitwithflexDirectionsothatitschildrenrenderaswe’dlikethem
to:


backdrop:{
flex:1,


flexDirection:'column'


}


Nowlet’sgivethe<Image>somechildren.Updatetherendermethodofthe
<WeatherProject>componenttoreturnthefollowing:



<Imagesource={require('image!flowers')}
resizeMode='cover'


style={styles.backdrop}>
<Viewstyle={styles.overlay}>
<Viewstyle={styles.row}>


</div>
<span class='text_page_counter'>(76)</span><div class='page_container' data-page=76>

Currentweatherfor
</Text>


<Viewstyle={styles.zipContainer}>
<TextInput


style={[styles.zipCode,styles.mainText]}
returnKeyType='go'


onSubmitEditing={this._handleTextChange}/>
</View>


</View>


<Forecast


main={this.state.forecast.main}


description={this.state.forecast.description}
temp={this.state.forecast.temp}/>


</View>



</Image>


</div>
<span class='text_page_counter'>(77)</span><div class='page_container' data-page=77>

<b>FetchingDatafromtheWeb</b>



Next,let’sexploreusingthenetworkingAPIsavailableinReactNative.Youwon’tbe
usingjQuerytosendAJAXrequestsfrommobiledevices!Instead,ReactNative
implementstheFetchAPI.ThePromise-basedsyntaxisfairlysimple:


fetch('')
.then((response)=>response.text())
.then((responseText)=>{


console.log(responseText);
});


WewillbeusingtheOpenWeatherMapAPI,whichprovidesuswithasimpleendpoint
thatreturnsthecurrentweatherforagivenzipcode.


TointegratethisAPI,wecanchangethecallbackonthe<TextInput>componenttoquery
theOpenWeatherMapAPI:


_handleTextChange:function(event){
varzip=event.nativeEvent.text;
this.setState({zip:zip});


fetch('+
zip+'&units=imperial')


.then((response)=>response.json())
.then((responseJSON)=>{



<i>//Takealookattheformat,ifyouwant.</i>


console.log(responseJSON);
this.setState({


forecast:{


main:responseJSON.weather[0].main,


description:responseJSON.weather[0].description,
temp:responseJSON.main.temp


}
});
})


.catch((error)=>{
console.warn(error);
});
}
NotethatwewanttheJSONfromtheresponse.TheFetchAPIisprettystraightforwardto
workwith,sothisisallwewillneedtodo.
Theotherthingthatwecandoistoremovetheplaceholderdata,andmakesurethatthe
forecastdoesnotrenderifwedonothavedatayet.
First,clearthemockdatafromgetInitialState:
getInitialState:function(){
return{


zip:'',


forecast:null
};


}


Then,intherenderfunction,updatetherenderinglogic:


<b>var</b>content=null;


<b>if(this.</b>state.forecast!==null){


</div>
<span class='text_page_counter'>(78)</span><div class='page_container' data-page=78>

main={this.state.forecast.main}


description={this.state.forecast.description}
temp={this.state.forecast.temp}/>;


}


</div>
<span class='text_page_counter'>(79)</span><div class='page_container' data-page=79>

<b>PuttingItTogether</b>



Forthefinalversionoftheapplication,I’vereorganizedthe<WeatherProject>


component’srenderfunctionandtweakedthestyles.Themainchangeistothelayout
logic,diagrammedinFigure3-18.


<i>Figure3-18.Layoutofthefinishedweatherapplication</i>


OK.Readytoseeitallinoneplace?Example3-11showsthefinishedcodeforthe
<WeatherProject>componentinfull,includingthestylesheets.The<Forecast>



componentwillbethesameasaboveinExample3-9.


<i>Example3-11.FinishedcodeforWeatherProject.js</i>


<b>var</b>React=require('react-native');
<b>var{</b>
StyleSheet,
Text,
View,
TextInput,
Image


}=React;


<b>var</b>Forecast=require('./Forecast');
<b>var</b>WeatherProject=React.createClass({
getInitialState:function(){


return{
zip:'',
forecast:null
};


},


</div>
<span class='text_page_counter'>(80)</span><div class='page_container' data-page=80>

fetch(' />


+zip+'&units=imperial')


.then((response)=>response.json())
.then((responseJSON)=>{



this.setState({
forecast:{


main:responseJSON.weather[0].main,


description:responseJSON.weather[0].description,
temp:responseJSON.main.temp


}
});
})


.catch((error)=>{
console.warn(error);
});


},


render:function(){
varcontent=null;


if(this.state.forecast!==null){
content=<Forecast


main={this.state.forecast.main}


description={this.state.forecast.description}
temp={this.state.forecast.temp}/>;



}


return(


<Viewstyle={styles.container}>


<Imagesource={require('image!flowers')}
resizeMode='cover'


style={styles.backdrop}>
<Viewstyle={styles.overlay}>
<Viewstyle={styles.row}>


<Textstyle={styles.mainText}>
Currentweatherfor


</Text>


<Viewstyle={styles.zipContainer}>
<TextInput


style={[styles.zipCode,styles.mainText]}
returnKeyType='go'


onSubmitEditing={this._handleTextChange}/>
</View>


</View>
{content}
</View>


</Image>
</View>
);


}
});


<b>var</b>baseFontSize=16;


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


alignItems:'center',
paddingTop:30


},


backdrop:{
flex:1,


flexDirection:'column'


},


overlay:{
paddingTop:5,


backgroundColor:'#000000',


opacity:0.5,


flexDirection:'column',
alignItems:'center'


},
row:{
flex:1,


flexDirection:'row',
flexWrap:'nowrap',
alignItems:'flex-start',
padding:30


</div>
<span class='text_page_counter'>(81)</span><div class='page_container' data-page=81>

zipContainer:{
flex:1,


borderBottomColor:'#DDDDDD',
borderBottomWidth:1,


marginLeft:5,
marginTop:3


},


zipCode:{
width:50,


height:baseFontSize,
},



mainText:{
flex:1,


fontSize:baseFontSize,
color:'#FFFFFF'


}
});


module.exports=WeatherProject;


Nowthatwe’redone,trylaunchingtheapplication.ItshouldworkonbothAndroidand
iOS,inanemulatororonyourphysicaldevice.Whatwouldyouliketochangeor


improve?


</div>
<span class='text_page_counter'>(82)</span><div class='page_container' data-page=82>

<b>Summary</b>



Forourfirstrealapplication,we’vealreadycoveredalotofground.Weintroducedanew
UIcomponent,<TextInput>,andlearnedhowtouseittogetinformationfromtheuser.
WedemonstratedhowtoimplementbasicstylinginReactNative,aswellashowtouse
imagesandincludeassetsinourapplication.Finally,welearnedhowtousetheReact
NativenetworkingAPItorequestdatafromexternalwebsources.Notbadforafirst
application!


Hopefully,thishasdemonstratedhowquicklyyoucanbuildReactNativeapplications
withusefulfeaturesthatfeelathomeonamobiledevice.


Ifyouwanttoextendyourapplicationfurther,herearesomethingstotry:



Addmoreimages,andchangethembasedontheforecast


Addvalidationtothezipcodefield


Switchtousingamoreappropriatekeypadforthezipcodeinput


Displaythefive-dayweatherforecast


Oncewecovermoretopics,suchasgeolocation,youwillbeabletoextendtheweather
applicationinevenmoreways.


</div>
<span class='text_page_counter'>(83)</span><div class='page_container' data-page=83></div>
<span class='text_page_counter'>(84)</span><div class='page_container' data-page=84>

<b>Chapter4.ComponentsforMobile</b>



InChapter3,webuiltasimpleweatherapp.Indoingso,wetoucheduponthebasicsof
buildinginterfaceswithReactNative.Inthischapter,wewilltakeacloserlookatthe
mobile-basedcomponentsusedforReactNative,andhowtheycomparetobasicHTML
elements.MobileinterfacesarebasedondifferentprimitiveUIelementsthanwebpages,
andthusweneedtousedifferentcomponents.


</div>
<span class='text_page_counter'>(85)</span><div class='page_container' data-page=85>

<b>AnalogiesBetweenHTMLElementsandNative</b>


<b>Components</b>



WhendevelopingfortheWeb,wemakeuseofavarietyofbasicHTMLelements.These
include<div>,<span>,and<img>,aswellasorganizationalelementssuchas<ol>,<ul>,
and<table>.(Wecouldincludeaconsiderationofelementssuchas<audio>,<svg>,


<canvas>,andsoon,butwe’llignorethemfornow.)


WhendealingwithReactNative,wedon’tusetheseHTMLelements,butweuseavariety


ofcomponentsthatarenearlyanalogoustothem(Table4-1).


<i>Table4-1.Analogous</i>
<i>HTMLandNative</i>


<i>components</i>
<b>HTML</b> <b>ReactNative</b>


div View


img Image


span,p Text


ul/ol,li ListView,childitems


Althoughtheseelementsserveroughlythesamepurposes,theyarenotinterchangeable.
Let’stakealookathowthesecomponentsworkonmobilewithReactNative,andhow
theydifferfromtheirbrowser-basedcounterparts.


<b>CANISHARECODEBETWEENREACTNATIVEANDMYWEBAPP?</b>


</div>
<span class='text_page_counter'>(86)</span><div class='page_container' data-page=86>

<b>TheTextComponent</b>


Renderingtextisadeceptivelybasicfunction;nearlyanyapplicationwillneedtorender
textsomewhere.However,textwithinthecontextofReactNativeandmobile
developmentworksdifferentlyfromtextrenderingfortheWeb.
WhenworkingwithtextinHTML,youcanincluderawtextstringsinavarietyof
elements.Furthermore,youcanstylethemwithchildtagssuchas<strong>and<em>.So,
youmightendupwithanHTMLsnippetthatlookslikethis:
<b><p>Thequick<em>brown</em>foxjumpedoverthelazy<strong>dog</strong>.</p></b>


InReactNative,only<Text>componentsmayhaveplaintextnodesaschildren.Inother
words,thisisnotvalid:
<b><View></b>
Textdoesn'tgohere!
<b></View></b>
Instead,wrapyourtextina<Text>component:
<b><View></b>
<Text>ThisisOK!</Text>
<b></View></b>


Whendealingwith<Text>componentsinReactNative,younolongerhaveaccessto
subtagssuchas<strong>and<em>,thoughyoucanapplystylestoachievesimilareffects
throughuseofattributessuchasfontWeightandfontStyle.Here’showyoumight


achieveasimilareffectbymakinguseofinlinestyles:
<Text>
Thequick<Textstyle={{fontStyle:"italic"}}>brown</Text>fox
jumpedoverthelazy<Textstyle={{fontWeight:"bold"}}>dog</Text>.
</Text>
Thisapproachcouldquicklybecomeverbose.You’lllikelywanttocreatestyled
componentsasasortofshorthandwhendealingwithtext,asshowninExample4-1.


<i>Example4-1.Creatingreusablecomponentsforstylingtext</i>


<b>var</b>styles=StyleSheet.create({
bold:{


fontWeight:"bold"



},


italic:{


fontStyle:"italic"


}
});


<b>var</b>Strong=React.createClass({
render:function(){


return(


<Textstyle={styles.bold}>
{this.props.children}
</Text>);


</div>
<span class='text_page_counter'>(87)</span><div class='page_container' data-page=87>

<b>var</b>Em=React.createClass({
render:function(){
return(


<Textstyle={styles.italic}>
{this.props.children}
</Text>);


}
});
Onceyouhavedeclaredthesestyledcomponents,youcanfreelymakeuseofstyled
nesting.NowtheReactNativeversionlooksquitesimilartotheHTMLversion(see


Example4-2).
<i>Example4-2.Usingstyledcomponentsforrenderingtext</i>


<Text>


Thequick<Em>brown</Em>foxjumped


overthelazy<Strong>dog</Strong>.
</Text>


Similarly,ReactNativedoesnotinherentlyhaveanyconceptofheaderelements(h1,h2,
etc.),butit’seasytodeclareyourownstyled<Text>elementsandusethemasneeded.


</div>
<span class='text_page_counter'>(88)</span><div class='page_container' data-page=88>

<b>TheImageComponent</b>



<i>Iftextisthemostbasicelementinanapplication,imagesareaclosecontender,forboth</i>
mobileandfortheWeb.WhenwritingHTMLandCSSfortheWeb,weincludeimagesin
avarietyofways:sometimesweusethe<img>tag,whileatothertimesweapplyimages
viaCSS,suchaswhenweusethebackground-imageproperty.InReactNative,wehavea
similar<Image>component,butitbehavesalittledifferently.


Thebasicusageofthe<Image>componentisstraightforward;justsetthesourceprop:


<Imagesource={require('image!puppies')}/>


Howdoesthatrequirecallwork?Wheredoesthisresourcelive?Here’sonepartofReact
Nativethatyou’llhavetoadjustbasedonwhichplatformyou’retargeting.OniOS,this
meansthatyou’llneedtoimportitintotheassetsfolderwithinyourXcodeproject.By
providingtheappropriate@2xand@3xresolutionfiles,youwillenableXcodetoserve
thecorrectassetfileforthecorrectplatform.Thisisanicechangefromwebdevelopment:


therelativelylimitedpossiblecombinationsofscreensizeandresolutiononiOSmeans
thatit’seasiertocreatetargetedassets.


ForReactNativeonotherplatforms,wecanexpectthattheimage!requiresyntaxwill
pointtoasimilarassetsdirectory.


It’sworthmentioningthatitisalsopossibletoincludeweb-basedimagesourcesinstead
ofbundlingyourassetswithyourapplication.Facebookdoesthisasoneoftheexamples
intheUIExplorerapplication:


<Imagesource={{uri:' />style={{width:400,height:400}}/>


Whenutilizingnetworkresources,youwillneedtospecifydimensionsmanually.
Downloadingimagesviathenetworkratherthanincludingthemasassetshassome
advantages.Duringdevelopment,forinstance,itmaybeeasiertousethisapproachwhile
prototyping,ratherthancarefullyimportingallofyourassetsaheadoftime.Italso
reducesthesizeofyourbundledmobileapplication,sothatusersneedn’tdownloadallof
yourassets.However,itmeansthatinsteadyou’llberelyingontheuser’sdataplan
whenevertheyaccessyourapplicationinthefuture.Formostcases,you’llwanttoavoid
usingtheURI-basedmethod.
Ifyou’rewonderingaboutworkingwiththeuser’sownimages,we’llcoverthecamera
rollinChapter6.


<i>BecauseReactNativeemphasizesacomponent-basedapproach,imagesmustbeincluded</i>
asan<Image>componentinsteadofbeingreferencedviastyles.Forinstance,in


Chapter3,wewantedtouseanimageasabackgroundforourweatherapplication.


</div>
<span class='text_page_counter'>(89)</span><div class='page_container' data-page=89>

applyabackgroundimage,inReactNativeyouinsteadusethe<Image>asacontainer
component,likeso:



<Imagesource={require('image!puppies')}>
{<i>/*Yourcontenthere…*/</i>}


</Image>


Stylingtheimagesthemselvesisfairlystraightforward.Inadditiontoapplyingstyles,
certainpropscontrolhowtheimagewillberendered.You’lloftenmakeuseofthe
resizeModeprop,forinstance,whichcanbesettoresize,cover,orcontain.The
UIExplorerappdemonstratesthiswell(Figure4-1).


<i>Figure4-1.Thedifferencebetweenresize,cover,andcontain</i>


</div>
<span class='text_page_counter'>(90)</span><div class='page_container' data-page=90>

<b>WorkingwithTouchandGestures</b>



Web-basedinterfacesareusuallydesignedformouse-basedcontrollers.Weusethingslike
hoverstatetoindicateinteractivityandrespondtouserinteraction.Formobile,it’stouch
thatmatters.Mobileplatformshavetheirownnormsaroundinteractionsthatyou’llwant
todesignfor.Thisvariessomewhatfromplatformtoplatform:iOSbehavesdifferently
fromAndroid,whichbehavesdifferentlyyetagainfromWindowsPhone.


</div>
<span class='text_page_counter'>(91)</span><div class='page_container' data-page=91>

<b>UsingTouchableHighlight</b>


Anyinterfaceelementsthatrespondtousertouch(thinkbuttons,controlelements,etc.)
shouldusuallyhavea<TouchableHighlight>wrapper.<TouchableHighlight>causesan
overlaytoappearwhentheviewistouched,givingtheuservisualfeedback.Thisisoneof
<i></i>
thekeyinteractionsthatcausesamobileapplicationtofeelnative,asopposedtoamobile-optimizedwebsite,wheretouchfeedbackislimited.Asageneralruleofthumb,you


shoulduse<TouchableHighlight>anywheretherewouldbeabuttonoralinkonthe
Web.



Atitsmostbasicusage,youjustneedtowrapyourcomponentina


<TouchableHighlight>,whichwilladdasimpleoverlaywhenpressed.The


<TouchableHighlight>componentalsogivesyouhooksforeventssuchasonPressIn,


onPressOut,onLongPress,andthelike,soyoucanusetheseeventsinyourReact


applications.


Example4-3showshowyoucanwrapacomponentina<TouchableHighlight>inorder
togivetheuserfeedback.


<i>Example4-3.Usingthe<TouchableHighlight>component</i>


<TouchableHighlight


onPressIn={this._onPressIn}
onPressOut={this._onPressOut}
style={styles.touchable}>
<Viewstyle={styles.button}>
<Textstyle={styles.welcome}>


{this.state.pressing?'EEK!':'PUSHME'}
</Text>


</View>


</TouchableHighlight>



</div>
<span class='text_page_counter'>(92)</span><div class='page_container' data-page=92>

<i>Figure4-2.Using<TouchableHighlight>togivetheuservisualfeedback—theunpressedstate(left)andthepressed</i>
<i>state,withhighlight(right)</i>


Thisisacontrivedexample,butitillustratesthebasicinteractionsthatmakeabutton
“feel”touchableonmobile.Theoverlayisakeypieceoffeedbackthatinformstheuser
thatanelementcanbepressed.Notethatinordertoapplytheoverlay,wedon’tneedto
applyanylogictoourstyles;the<TouchableHighlight>handlesthelogicofthatforus.


Example4-4showsthefullcodeforthisbuttoncomponent.


<i>Example4-4.Touch/PressDemo.jsillustratestheuseof<TouchableHighlight></i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>


StyleSheet,
Text,
View,


TouchableHighlight


}=React;


</div>
<span class='text_page_counter'>(93)</span><div class='page_container' data-page=93>

pressing:false
}


},



_onPressIn:function(){


this.setState({pressing:true});
},


_onPressOut:function(){


this.setState({pressing:false});
},


render:function(){
return(


<Viewstyle={styles.container}>
<TouchableHighlight


onPressIn={this._onPressIn}
onPressOut={this._onPressOut}
style={styles.touchable}>
<Viewstyle={styles.button}>
<Textstyle={styles.welcome}>


{this.state.pressing?'EEK!':'PUSHME'}
</Text>


</View>


</TouchableHighlight>
</View>



);
}
});


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


justifyContent:'center',
alignItems:'center',
backgroundColor:'#F5FCFF',
},


welcome:{
fontSize:20,


textAlign:'center',
margin:10,


color:'#FFFFFF'


},


touchable:{


borderRadius:100


},



button:{


backgroundColor:'#FF0000',
borderRadius:100,


height:200,
width:200,


justifyContent:'center'


},
});


module.exports=Button;


Tryeditingthisbuttontorespondtootherevents,byusinghookslikeonPressand


onLongPress.Thebestwaytogetasenseforhowtheseeventsmapontouserinteractions


</div>
<span class='text_page_counter'>(94)</span><div class='page_container' data-page=94>

<b>TheGestureResponderSystem</b>



Whatifyouwanttodomorethanjustmakethings“tappable”?ReactNativealsoexposes
twoAPIsforcustomtouchhandling:GestureResponderandPanResponder.


GestureResponderisalower-levelAPI,whilePanResponderprovidesauseful


abstraction.We’llstartbylookingathowtheGestureRespondersystemworks,because
it’sthebasisforthePanResponderAPI.


Touchonmobileisfairlycomplicated.Mostmobileplatformssupportmultitouch,which


meansthattherecanbemultipletouchpointsactiveonthescreenatonce.(Notallof
thesearenecessarilyfingers,either;thinkaboutthedifficultyof,forexample,detecting
theuser’spalmrestingonthecornerofthescreen.)Additionally,there’stheissueof
whichviewshouldhandleagiventouch.Thisproblemissimilartohowmouseeventsare
processedontheWeb,andthedefaultbehaviorisalsosimilar:thetopmostchildhandles
thetoucheventbydefault.WithReactNative’sgesturerespondersystem,however,we
canoverridethisbehaviorifwesochoose.


<i>Thetouchresponderistheviewthathandlesagiventouchevent.Intheprevioussection,</i>
wesawthatthe<TouchableHighlight>componentactsasatouchresponder.Wecan
causeourowncomponentstobecomethetouchresponder,too.Thelifecyclebywhich
thisprocessisnegotiatedisalittlecomplicated.Aviewthatwishestoobtaintouch
responderstatusshouldimplementfourprops:


View.props.onStartShouldSetResponder


View.props.onMoveShouldSetResponder


View.props.onResponderGrant


View.props.onResponderReject


</div>
<span class='text_page_counter'>(95)</span><div class='page_container' data-page=95>

<i>Figure4-3.Obtainingtouchresponderstatus</i>


Yikes,thatlookscomplicated!Let’steasethisapart.First,atoucheventhasthreemain
<i>lifecyclestages:start,move,andrelease(thesecorrespondto</i>mouseDown,mouseMove,and


mouseUp<i>inthebrowser).Aviewcanrequesttobethetouchresponderduringthestartor</i>


<i>themovephase.ThisbehaviorisspecifiedbyonStartShouldSetResponderand</i>



onMoveShouldSetResponder.Whenoneofthosefunctionsreturnstrue,theviewattempts
toclaimresponderstatus.


<i>Afteraviewhasattemptedtoclaimresponderstatus,itsattemptmaybegrantedor</i>


<i>rejected.Theappropriatecallback—either</i>onResponderGrantoronResponderReject—
willbeinvoked.


Therespondernegotiationfunctionsarecalledinabubblingpattern.Ifmultipleviews
attempttoclaimresponderstatus,thedeepestcomponentwillbecometheresponder.This
istypicallythedesiredbehavior;otherwise,youwouldhavedifficultyaddingtouchable
componentssuchasbuttonstoalargerview.Ifyouwanttooverridethisbehavior,parent
componentscanmakeuseofonStartShouldSetResponderCaptureand


onMoveShouldSetResponderCapture.Returningtruefromeitherofthesewillpreventa


component’schildrenfrombecomingthetouchresponder.


</div>
<span class='text_page_counter'>(96)</span><div class='page_container' data-page=96>

<i>View.props.onResponderMove</i>
Theuserismovingherfinger
<i>View.props.onResponderRelease</i>
Firedattheendofthetouch(i.e.,“touchUp”)
<i>View.props.onResponderTerminationRequest</i>
Somethingelsewantstobecomeresponder.Shouldthisviewreleasetheresponder?
Returningtrueallowsrelease


<i>View.props.onResponderTerminate</i>


</div>
<span class='text_page_counter'>(97)</span><div class='page_container' data-page=97>

Thisisafairlylow-levelAPI;ifyouwanttodetectandrespondtogesturesinthisway,


youwillneedtospendadecentamountoftimetuningthecorrectparametersandfiguring
outwhichvaluesyoushouldcareabout.Inthenextsection,wewilltakealookat


</div>
<span class='text_page_counter'>(98)</span><div class='page_container' data-page=98>

<b>PanResponder</b>



Unlike<TouchableHighlight>,PanResponderisnotacomponent,butratheraclass
providedbyReactNative.Itprovidesaslightlyhigher-levelAPIthanthebasicevents
returnedbytheGestureRespondersystem,whilestillprovidingaccesstothoseraw
events.APanRespondergestureStateobjectgivesyouaccesstothefollowing,in
accordancewiththePanResponderdocumentation:


<i>stateID</i>


IDofthegestureState(persistedaslongasthereatleastonetouchonscreen)


<i>moveX</i>
Thelatestscreencoordinatesoftherecentlymovedtouch
<i>moveY</i>
Thelatestscreencoordinatesoftherecentlymovedtouch
<i>x0</i>
Thescreencoordinatesoftherespondergrant
<i>y0</i>
Thescreencoordinatesoftherespondergrant
<i>dx</i>
Accumulateddistanceofthegesturesincethetouchstarted
<i>dy</i>
Accumulateddistanceofthegesturesincethetouchstarted
<i>vx</i>
Currentvelocityofthegesture
<i>vy</i>


Currentvelocityofthegesture
<i>numberActiveTouches</i>
Numberoftouchescurrentlyonscreeen
Asyoucansee,inadditiontorawpositiondata,agestureStateobjectalsoincludes
informationsuchasthecurrentvelocityofthetouchandtheaccumulateddistance.
TomakeuseofPanResponderinacomponent,weneedtocreateaPanResponderobject
andthenattachittoacomponentintherendermethod.
CreatingaPanResponderrequiresustospecifytheproperhandlersforPanResponder
events(Example4-5).


<i>Example4-5.CreatingaPanResponderrequiresustopassabunchofcallbacks</i>


<b>this.</b>_panResponder=PanResponder.create({


</div>
<span class='text_page_counter'>(99)</span><div class='page_container' data-page=99>

onPanResponderGrant:this._handlePanResponderGrant,
onPanResponderMove:this._handlePanResponderMove,
onPanResponderRelease:this._handlePanResponderEnd,
onPanResponderTerminate:this._handlePanResponderEnd,
});


Then,weusespreadsyntaxtoattachthePanRespondertotheviewinthecomponent’s


rendermethod(Example4-6).


<i>Example4-6.AttachingthePanResponderusingspreadsytax</i>


render:function(){
return(


<View



{...this._panResponder.panHandlers}>
{<i>/*Viewcontentshere*/</i>}


</View>
);


}


Afterthis,thehandlersthatyoupassedtothePanResponder.createcallwillbeinvoked
duringtheappropriatemoveevents,ifthetouchoriginateswithinthisview.


Example4-7showsamodifiedversionofthePanResponderexamplecodeprovidedby
ReactNative.Thisversionlistenstotoucheventsonthecontainerview,asopposedtojust
thecircle,andsothatthevaluesareprintedtothescreenasyouinteractwiththe


</div>
<span class='text_page_counter'>(100)</span><div class='page_container' data-page=100></div>
<span class='text_page_counter'>(101)</span><div class='page_container' data-page=101>

<i>Figure4-4.PanResponderdemo</i>
<i>Example4-7.Touch/PanDemo.jsillustratestheuseofPanResponder</i>
<i>//Adaptedfrom</i>
<i>// /><i>//Examples/UIExplorer/PanResponderExample.js</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>


StyleSheet,
PanResponder,
View,


Text



}=React;


<b>var</b>CIRCLE_SIZE=40;
<b>var</b>CIRCLE_COLOR='blue';


<b>var</b>CIRCLE_HIGHLIGHT_COLOR='green';


<b>var</b>PanResponderExample=React.createClass({
<i>//Setsomeinitialvalues.</i>


_panResponder:{},
_previousLeft:0,
_previousTop:0,
_circleStyles:{},
circle:null,


getInitialState:function(){
return{


numberActiveTouches:0,
moveX:0,


moveY:0,
x0:0,
y0:0,
dx:0,
dy:0,
vx:0,
vy:0,


}


},


componentWillMount:function(){


this._panResponder=PanResponder.create({


onStartShouldSetPanResponder:this._handleStartShouldSetPanResponder,
onMoveShouldSetPanResponder:this._handleMoveShouldSetPanResponder,
onPanResponderGrant:this._handlePanResponderGrant,


onPanResponderMove:this._handlePanResponderMove,
onPanResponderRelease:this._handlePanResponderEnd,
onPanResponderTerminate:this._handlePanResponderEnd,
});


this._previousLeft=20;
this._previousTop=84;
this._circleStyles={
left:this._previousLeft,
top:this._previousTop,
};


},


componentDidMount:function(){
this._updatePosition();
},



render:function(){
return(


<Viewstyle={styles.container}>
<View


ref={(circle)=>{
this.circle=circle;
}}


style={styles.circle}


</div>
<span class='text_page_counter'>(102)</span><div class='page_container' data-page=102>

<Text>


{this.state.numberActiveTouches}touches,
dx:{this.state.dx},


dy:{this.state.dy},
vx:{this.state.vx},
vy:{this.state.vy}
</Text>


</View>
);


},


<i>//_highlightand_unHighlightgetcalledbyPanRespondermethods,</i>


<i>//providingvisualfeedbacktotheuser.</i>



_highlight:function(){


this.circle&&this.circle.setNativeProps({
backgroundColor:CIRCLE_HIGHLIGHT_COLOR


});
},


_unHighlight:function(){


this.circle&&this.circle.setNativeProps({
backgroundColor:CIRCLE_COLOR


});
},


<i>//We'recontrollingthecircle'spositiondirectlywithsetNativeProps.</i>


_updatePosition:function(){


this.circle&&this.circle.setNativeProps(this._circleStyles);
},


_handleStartShouldSetPanResponder:


function(e:Object,gestureState:Object):boolean{


<i>//Shouldwebecomeactivewhentheuserpressesdownonthecircle?</i>



returntrue;
},


_handleMoveShouldSetPanResponder:


function(e:Object,gestureState:Object):boolean{


<i>//Shouldwebecomeactivewhentheusermovesatouchoverthecircle?</i>


returntrue;
},


_handlePanResponderGrant:function(e:Object,gestureState:Object){
this._highlight();


},


_handlePanResponderMove:function(e:Object,gestureState:Object){
this.setState({


stateID:gestureState.stateID,
moveX:gestureState.moveX,
moveY:gestureState.moveY,
x0:gestureState.x0,
y0:gestureState.y0,
dx:gestureState.dx,
dy:gestureState.dy,
vx:gestureState.vx,
vy:gestureState.vy,



numberActiveTouches:gestureState.numberActiveTouches


});


<i>//Calculatecurrentpositionusingdeltas</i>


this._circleStyles.left=this._previousLeft+gestureState.dx;
this._circleStyles.top=this._previousTop+gestureState.dy;
this._updatePosition();


},


_handlePanResponderEnd:function(e:Object,gestureState:Object){
this._unHighlight();


this._previousLeft+=gestureState.dx;
this._previousTop+=gestureState.dy;
},


});


<b>var</b>styles=StyleSheet.create({
circle:{


</div>
<span class='text_page_counter'>(103)</span><div class='page_container' data-page=103>

borderRadius:CIRCLE_SIZE/2,
backgroundColor:CIRCLE_COLOR,
position:'absolute',


left:0,
top:0,


},


container:{
flex:1,


paddingTop:64,
},


});


module.exports=PanResponderExample;
<b>Choosinghowtohandletouch</b>


HowshouldyoudecidewhentousethetouchandgestureAPIsdiscussedinthissection?
Itdependsonwhatyouwanttobuild.


Inordertoprovidetheuserwithbasicfeedback,andindicatethatabuttonoranother
elementis“tappable,”usethe<TouchableHighlight>component.


Inordertoimplementyourowncustomtouchinterfaces,useeithertherawGesture


Respondersystem,oraPanResponder.Chancesarethatyouwillalmostalwayspreferthe
PanResponderapproach,becauseitalsogivesyouaccesstothesimplertouchevents
providedbytheGestureRespondersystem.Ifyouaredesigningagame,oranapplication
withanunusualinterface,you’llneedtospendsometimebuildingouttheinteractionsyou
wantbyusingtheseAPIs.


</div>
<span class='text_page_counter'>(104)</span><div class='page_container' data-page=104>

<b>WorkingwithOrganizationalComponents</b>



Inthissection,we’regoingtolookatorganizationalcomponentsthatyoucanuseto


controlgeneralflowwithinyourapplication.Thisincludesthe<TabView>,


<NavigatorView>,and<ListView>,whichallimplementsomeofthemostcommon


mobileinteractionandnavigationalpatterns.Onceyouhaveplannedoutyour


</div>
<span class='text_page_counter'>(105)</span><div class='page_container' data-page=105>

<b>UsingListView</b>



Let’sstartbyusingthe<ListView>component.Inthissection,wearegoingtobuildan
<i>appthatdisplaystheNewYorkTimesBestSellerListandletsusviewdataabouteach</i>
book,asshowninFigure4-5.Ifyou’dlike,youcangrabyourownAPItokenfromthe


</div>
<span class='text_page_counter'>(106)</span><div class='page_container' data-page=106></div>
<span class='text_page_counter'>(107)</span><div class='page_container' data-page=107>

<i>Figure4-5.TheBookListapplicationwe’llbebuilding</i>


Listsareextremelyusefulformobiledevelopment,andyouwillnoticethatmanymobile
userinterfacesfeaturethemasacentralelement.A<ListView>isliterallyjustalistof
views,optionallywithspecialviewsforsectiondividers,headers,orfooters.Forexample,
youcanseethisinteractionpatternintheDropbox,Twitter,andiOSSettingsapps


(Figure4-6).


<i>Figure4-6.ListsasusedbyDropbox,Twitter,andtheiOSSettingsapp</i>


<ListView>sareagoodexampleofwhereReactNativeshines,becauseitcanleverageits
hostplatform.Onmobile,thenative<ListView>elementisusuallyhighlyoptimizedso
thatrenderingissmoothandstutter-free.Ifyouexpecttorenderaverylargenumberof
itemsinyour<ListView>,youshouldtrytokeepthechildviewsrelativelysimple,totry
andreducestutter.


ThebasicReactNative<ListView>componentrequirestwoprops:dataSourceand



renderRow.dataSourceis,asthenameimplies,asourceofinformationaboutthedata


thatneedstoberendered.renderRowshouldreturnacomponentbasedonthedatafrom
oneelementofthedataSource.


<i>ThisbasicusageisdemonstratedinSimpleList.js.We’llstartbyaddinga</i>dataSourceto
our<SimpleList>component.AListView.DataSourceneedstoimplementthe


rowHasChangedmethod.Here’sasimpleexample:


</div>
<span class='text_page_counter'>(108)</span><div class='page_container' data-page=108>

TosettheactualcontentsofadataSource,weusecloneWithRows.Let’sreturnthe


dataSourceinourgetInitialStatecall:


getInitialState:function(){


vards=newListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
return{


dataSource:ds.cloneWithRows(['a','b','c','alongerexample','d','e'])
};


}


TheotherpropweneedisrenderRow,whichshouldbeafunctionthatreturnssomeJSX
basedonthedataforagivenrow:


_renderRow:function(rowData){



return<Textstyle={styles.row}>{rowData}</Text>;
}


Nowwecanputitalltogethertoseeasimple<ListView>,byrenderinga<ListView>
likeso:


<ListView


dataSource={this.state.dataSource}
renderRow={this._renderRow}


/>


</div>
<span class='text_page_counter'>(109)</span><div class='page_container' data-page=109></div>
<span class='text_page_counter'>(110)</span><div class='page_container' data-page=110>

<i>Figure4-7.TheSimpleListcomponentrendersabarebones<ListView></i>


Whatifwewanttodoalittlemore?Let’screatea<ListView>withmorecomplexdata.
WewillbeusingtheNewYorkTimesAPItocreateasimpleBestSellersapplication,
whichrenderstheNewYorkTimesBestSellerlist.


First,weinitializeourdatasourcetobeempty,becausewe’llneedtofetchthedata:


getInitialState:function(){


vards=newListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
return{


dataSource:ds.cloneWithRows([])
};


}



Then,weaddamethodforfetchingdata,andupdatethedatasourceoncewehaveit.This
methodwillgetcalledfromcomponentDidMount:


_refreshData:function(){
varendpoint=


' />=json&api-key='+API_KEY;


fetch(endpoint)


.then((response)=>response.json())
.then((rjson)=>{


this.setState({


dataSource:this.state.dataSource.cloneWithRows(rjson.results.books)
});


});
}


EachbookreturnedbytheNewYorkTimesAPIhasthreeproperties:coverURL,author,
andtitle.Weupdatethe<ListView>’srenderfunctiontoreturnacomponentbasedon
thoseprops.


<i>Example4-8.For_renderRow,wejustpassalongtherelevantdatatothe<BookItem></i>


_renderRow:function(rowData){



return<BookItemcoverURL={rowData.book_image}
title={rowData.title}


author={rowData.author}/>;
},


We’llalsotossinaheaderandfootercomponent,todemonstratehowthesework
(Example4-9).Notethatfora<ListView>,theheaderandfooterarenotsticky;they
scrollwiththerestofthelist.Ifyouwantastickyheaderorfooter,it’sprobablyeasiestto
renderthemseparatelyfromthe<ListView>component.


<i>Example4-9.AddingmethodstorenderheaderandfooterelementsinBookListV2.js</i>


_renderHeader:function(){


return(<Viewstyle={styles.sectionDivider}>
<Textstyle={styles.headingText}>


BestsellersinHardcoverFiction


</Text>
</View>);
},


_renderFooter:function(){
return(


</div>
<span class='text_page_counter'>(111)</span><div class='page_container' data-page=111>

DatafromtheNewYorkTimesBestSellerlist.
</Text>



</View>
);
},


<i>Alltogether,theBestSellersapplicationconsistsoftwofiles:BookListV2.jsand</i>


<i>BookItem.js.BookListV2.jsisshownin</i>Example4-10<i>.(BookList.jsisasimplerfilethat</i>
omitsfetchingdatafromanAPI,andisincludedintheGitHubrepositoryforyour
reference.)


<i>Example4-10.Bestsellers/BookListV2.js</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>
StyleSheet,
Text,
View,
Image,
ListView,
}=React;


<b>var</b>BookItem=require('./BookItem');


<b>var</b>API_KEY='73b19491b83909c7e07016f4bb4644f9:2:60667290';
<b>var</b>QUERY_TYPE='hardcover-fiction';


<b>var</b>API_STEM=' />


<b>var</b>ENDPOINT=`${API_STEM}/${QUERY_TYPE}?response-format=json&api-key=${API_KEY}`;
<b>var</b>BookList=React.createClass({



getInitialState:function(){


vards=newListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
return{


dataSource:ds.cloneWithRows([])
};


},


componentDidMount:function(){
this._refreshData();


},


_renderRow:function(rowData){


return<BookItemcoverURL={rowData.book_image}
title={rowData.title}


author={rowData.author}/>;
},


_renderHeader:function(){


return(<Viewstyle={styles.sectionDivider}>
<Textstyle={styles.headingText}>


BestsellersinHardcoverFiction



</Text>
</View>);
},


_renderFooter:function(){
return(


<Viewstyle={styles.sectionDivider}>


<Text>DatafromtheNewYorkTimesBestSellerlist.</Text>
</View>


);
},


_refreshData:function(){
fetch(ENDPOINT)


.then((response)=>response.json())
.then((rjson)=>{


this.setState({


dataSource:this.state.dataSource.cloneWithRows(rjson.results.books)
});


</div>
<span class='text_page_counter'>(112)</span><div class='page_container' data-page=112>

render:function(){
return(



<ListView


style=


dataSource={this.state.dataSource}
renderRow={this._renderRow}


renderHeader={this._renderHeader}
renderFooter={this._renderFooter}
/>


);
}
});


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


justifyContent:'center',
alignItems:'center',
backgroundColor:'#FFFFFF',
paddingTop:24


},
list:{
flex:1,


flexDirection:'row'



},


listContent:{
flex:1,


flexDirection:'column'


},
row:{
flex:1,
fontSize:24,
padding:42,
borderWidth:1,


borderColor:'#DDDDDD'


},


sectionDivider:{
padding:8,


backgroundColor:'#EEEEEE',
alignItems:'center'


},


headingText:{
flex:1,
fontSize:24,


alignSelf:'center'


}
});


module.exports=BookList;


The<BookItem>isasimplecomponentthathandlesrenderingeachchildviewinthelist
(Example4-11).


<i>Example4-11.Bestsellers/BookItem.js</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>
StyleSheet,
Text,
View,
Image,
ListView,
}=React;


<b>var</b>styles=StyleSheet.create({
bookItem:{


flex:1,


</div>
<span class='text_page_counter'>(113)</span><div class='page_container' data-page=113>

padding:5


},


cover:{
flex:1,
height:150,


resizeMode:'contain'


},
info:{
flex:3,


alignItems:'flex-end',
flexDirection:'column',
alignSelf:'center',
padding:20


},


author:{
fontSize:18


},
title:{


fontSize:18,
fontWeight:'bold'


}
});


<b>var</b>BookItem=React.createClass({


propTypes:{


coverURL:React.PropTypes.string.isRequired,
author:React.PropTypes.string.isRequired,
title:React.PropTypes.string.isRequired


},


render:function(){
return(


<Viewstyle={styles.bookItem}>


<Imagestyle={styles.cover}source=/>
<Viewstyle={styles.info}>


<Textstyle={styles.author}>{this.props.author}</Text>
<Textstyle={styles.title}>{this.props.title}</Text>
</View>


</View>
);
}
});


module.exports=BookItem;


</div>
<span class='text_page_counter'>(114)</span><div class='page_container' data-page=114>

<b>UsingNavigators</b>



The<ListView>isagoodexampleofcombiningmultipleviewstogetherintoamore


usableinteraction.Onahigherlevel,wecanusecomponentssuchasthe<Navigator>to
presentdifferentscreensofanapp,muchaswemighthavevariouspagesonawebsite.


The<Navigator>isasubtlebutimportantcomponent,andisusedinmanycommon
applications.Forinstance,theiOSSettingsappcouldbeimplementedasacombinationof
<Navigator>withmany<ListView>components(Figure4-8).TheDropboxappalso


</div>
<span class='text_page_counter'>(115)</span><div class='page_container' data-page=115>

<i>Figure4-8.TheiOSSettingsappisagoodexampleofNavigatorbehavior</i>


A<Navigator>allowsyourapplicationtotransitionbetweendifferentscreens(often
referredtoas“scenes”),whilemaintaininga“stack”ofroutes,sothatyoucanpush,pop,
orreplacestates.YoucanthinkofthisasanalogoustothehistoryAPIontheWeb.A
“route”isthetitleofascreen,coupledwithanindex.


Forinstance,intheSettingsapp,initiallythestackisempty.Whenyouselectoneofthe
submenus,theinitialsceneispushedontothestack.Tapping“back,”inthetop-leftcorner
ofthescreen,willpopitbackoff.


Ifyou’reinterestedinhowthisplaysout,theUIExplorerapphasagooddemoofthe
variouswaysofusingtheNavigatorAPI.


NotethatthereareactuallytwoNavigatoroptions:thecross-platform<Navigator>
componentandthe<NavigatorIOS>component.Inthisbook,we’llbeoptingtousethe


</div>
<span class='text_page_counter'>(116)</span><div class='page_container' data-page=116>

<b>SHOULDIUSENAVIGATORORNAVIGATORIOS?</b>


Funnyyoushouldask!TheReactNativedocshaveapageaddressingthatexactquestion.Theshortansweris:you
shouldusethe<Navigator>.<NavigatorIOS>isnotsupportedbythecoreteam,andhencehassomebugs.


</div>
<span class='text_page_counter'>(117)</span><div class='page_container' data-page=117>

<b>OtherOrganizationalComponents</b>




Thereareplentyofotherorganizationalcomponents,too.Forexample,afewusefulones
include<TabBarIOS>and<SegmentedControlIOS>(illustratedinFigure4-9)and


<DrawerLayoutAndroid>and<ToolbarAndroid>(illustratedinFigure4-10).


You’llnoticethattheseareallnamedwithplatform-specificsuffixes.That’sbecausethey
wrapnativeAPIsforplatform-specificUIelements.


<i>Figure4-9.AniOSsegmentedcontrol(top),andaniOStabbar(bottom)</i>


<i>Figure4-10.AnAndroidtoolbar(left),andanAndroiddrawer(right)</i>


</div>
<span class='text_page_counter'>(118)</span><div class='page_container' data-page=118>

betweenmultiplemodesorfunctions.<SegmentedControlIOS>and<ToolbarAndroid>
arebettersuitedformorefine-grainedcontrols.


You’llwanttorefertotheplatform-specificdesignguidelinesforhowbesttousethese
components:


AndroidDesignGuide


iOSHumanInterfaceGuidelines


</div>
<span class='text_page_counter'>(119)</span><div class='page_container' data-page=119>

<b>Platform-SpecificComponents</b>



Notallcomponentsareavailableonallplatforms,andnotallinteractionpatternsare
appropriateforalldevices.Thatdoesn’tmeanthatyoucan’tuseplatform-specificcodein
yourapplication,though!Inthissection,we’llcoverplatform-specificcomponents,as
wellasstrategiesforhowtoincorporatetheminyourcross-platformapplications.



<b>TIP</b>


</div>
<span class='text_page_counter'>(120)</span><div class='page_container' data-page=120>

<b>iOS-orAndroid-OnlyComponents</b>



Somecomponentsareonlyavailableonaspecificplatform.Thisincludesthingslike
<TabBarIOS>or<SwitchAndroid>.They’reusuallyplatform-specificbecausetheywrap

somekindofunderlyingplatform-specificAPI.Forsomecomponents,havingaplatform-agnosticversiondoesn’tmakesense.Forinstance,the<ToolbarAndroid>component
exposesanAndroid-specificAPIforaviewtypethatdoesn’texistoniOSanyway.


Platform-specificcomponentsarenamedwithanappropriatesuffix:eitherIOSor


Android.Ifyoutrytoincludeoneonthewrongplatform,yourapplicationwillcrash.


Componentscanalsohaveplatform-specificprops.Thesearetaggedinthedocumentation
withasmallbadgeindicatingtheirusage.Forinstance,<TextInput>hassomepropsthat
areplatform-agnostic,andothersthatarespecifictoiOSorAndroid(Figure4-11).


</div>
<span class='text_page_counter'>(121)</span><div class='page_container' data-page=121>

<b>ComponentswithPlatform-SpecificVersions</b>


So,howdoyouhandleplatform-specificcomponentsorpropsinacross-platform
application?Thegoodnewsisthatyoucanstillusethesecomponents.Rememberhow
<i>ourapphasbothanindex.ios.jsandanindex.android.jsfile?Thisnamingconventioncan</i>
beusedforanyfile,tocreateacomponentthathasdifferentimplementationsonAndroid
andiOS.
Asanexample,we’llusethe<SwitchIOS>and<SwitchAndroid>components.They
exposeslightlydifferentAPIs,butwhatifwejustwanttouseasimpleswitch?Let’s
createawrappercomponent,<Switch>,whichrenderstheappropriateplatform-specific
component.


<i>We’llstartbyimplementingswitch.ios.js(</i>Example4-12).It’saverysimplewrapper


around<SwitchIOS>,andallowsustoprovideacallbackforwhentheswitchvalue
changes.


<i>Example4-12.Switch.ios.js</i>


<b>var</b>React=require('react-native');


<b>var{</b>SwitchIOS}=React;


<b>var</b>Switch=React.createClass({
getInitialState(){


return{value:false};
},


_onValueChange(value){


this.setState({value:value});
if(this.props.onValueChange){
this.props.onValueChange(value);
}


},


render(){
return(
<SwitchIOS


onValueChange={this._onValueChange}
value={this.state.value}/>



);
}
});


module.exports=Switch;


<i>Next,let’simplementswitch.android.js(</i>Example4-13).


<i>Example4-13.Switch.android.js</i>


<b>var</b>React=require('react-native');


<b>var{</b>SwitchAndroid}=React;


<b>var</b>Switch=React.createClass({
getInitialState(){


return{value:false};
},


_onValueChange(value){


this.setState({value:value});
if(this.props.onValueChange){
this.props.onValueChange(value);
}


},



</div>
<span class='text_page_counter'>(122)</span><div class='page_container' data-page=122>

<SwitchAndroid


onValueChange={this._onValueChange}
value={this.state.value}/>


);
}
});


module.exports=Switch;


<i>Notethatitlooksalmostidenticaltoswitch.ios.js,anditimplementsthesameAPI.The</i>
onlydifferenceisthatituses<SwitchAndroid>internallyinsteadof<SwitchIOS>.


Wecannowimportour<Switch>componentfromanotherfilewiththesyntax:


<b>var</b>Switch=require('./switch');
...


<b>var</b>switchComp=<SwitchonValueChange={(val)=>{console.log(val);}}/>;


Let’sactuallyusethe<Switch><i>component.Createanewfile,CrossPlatform.js,and</i>
includethecodeshowninExample4-14.We’llhavethebackgroundcolorchangebased
onthecurrentvalueofa<Switch>.


<i>Example4-14.CrossPlatform.jsmakesuseofthe<Switch>component</i>


<b>var</b>React=require('react-native');
<b>var{</b>



StyleSheet,
Text,
View,
}=React;


<b>var</b>Switch=require('./switch');
<b>var</b>CrossPlatform=React.createClass({
getInitialState(){


return{val:false};
},


_onValueChange(val){


this.setState({val:val});
},


render:function(){


varcolorClass=this.state.val?styles.blueContainer:styles.redContainer;
return(


<Viewstyle={[styles.container,colorClass]}>
<Textstyle={styles.welcome}>


Makemeblue!
</Text>


<SwitchonValueChange={this._onValueChange}/>
</View>



);
}
});


<b>var</b>styles=StyleSheet.create({
container:{


flex:1,


justifyContent:'center',
alignItems:'center',
},


blueContainer:{


backgroundColor:'#5555FF'


},


redContainer:{


backgroundColor:'#FF5555'


},


welcome:{
fontSize:20,


</div>
<span class='text_page_counter'>(123)</span><div class='page_container' data-page=123>

}


});


module.exports=CrossPlatform;


<i>Notethatthere’snoswitch.jsfile,butwecancallrequire(./switch)</i>.TheReactNative
packagerwillautomaticallyselectthecorrectimplementationbasedonourplatform,and
<i>useeitherswitch.ios.jsorswitch.android.jsasappropriate.</i>


<i>Finally,replacethecontentsofindex.android.jsandindex.ios.jssothatwecanrenderthe</i>
<CrossPlatform>component.


<i>Example4-15.Theindex.ios.jsandindex.android.jsfilesshouldbeidentical,andsimply</i>
<i>importthecrossplatform.jsfile</i>


<b>var</b>React=require('react-native');


<b>var{</b>AppRegistry}=React;


<b>var</b>CrossPlatform=require('./crossplatform');


AppRegistry.registerComponent('PlatformSpecific',()=>CrossPlatform);


</div>
<span class='text_page_counter'>(124)</span><div class='page_container' data-page=124></div>
<span class='text_page_counter'>(125)</span><div class='page_container' data-page=125>

<b>WhentoUsePlatform-SpecificComponents</b>



Whenisitappropriatetouseaplatform-specificcomponent?Inmostcases,you’llwantto
dosowhenthere’saplatform-specificinteractionpatternthatyouwantyourapplicationto
adhereto.Ifyouwantyourapplicationtofeeltruly“native,”it’sworthpayingattentionto
platform-specificUInorms.


AppleandGooglebothprovidehumaninterfaceguidelinesfortheirplatforms,whichare


worthconsulting:


iOSHumanInterfaceGuidelines


AndroidDesignReference


Bycreatingplatform-specificversionsofonlycertaincomponents,youcanstrikea


</div>
<span class='text_page_counter'>(126)</span><div class='page_container' data-page=126>

<b>Summary</b>



Inthischapter,wedugintothespecificsofavarietyofthemostimportantcomponentsin
ReactNative.Wediscussedhowtoutilizebasiclow-levelcomponents,like<Text>and


<Image>,aswellashigher-ordercomponentslike<ListView>,<Navigator>,and


<TabBarIOS>.Wealsotookalookathowtousevarioustouch-focusedAPIsand


components,incaseyouwanttobuildyourowncustomtouchhandlers.Finally,wesaw
howtouseplatform-specificcomponentsinourapplications.


Atthispoint,youshouldbeequippedtobuildbasic,functionalapplicationsusingReact
Native!Nowthatyou’veacquaintedyourselfwiththecomponentsdiscussedinthis
chapter,buildinguponthemandcombiningthemtocreateyourownapplicationsshould
feelremarkablysimilartoworkingwithReactontheWeb.


</div>
<span class='text_page_counter'>(127)</span><div class='page_container' data-page=127></div>
<span class='text_page_counter'>(128)</span><div class='page_container' data-page=128>

<b>Chapter5.Styles</b>



It’sgreattobeabletobuildfunctionalapplications,butifyoucan’tstylethemeffectively,
youwon’tgetveryfar!InChapter3,webuiltasimpleweatherapplicationwithsome
basicstyles.WhilethisgaveusanoverviewofhowtostyleReactNativecomponents,we


glossedovermanyofthedetails.Inthischapter,wewilltakeacloserlookathowstyles
workinReactNative.We’llcoverhowtocreateandmanageyourstylesheets,aswellas
thedetailsofReactNative’simplementationofCSSrules.Bytheendofthischapter,you
shouldfeelcomfortablecreatingandstylingyourownReactNativecomponentsand
applications.


</div>
<span class='text_page_counter'>(129)</span><div class='page_container' data-page=129>

<b>DeclaringandManipulatingStyles</b>



WhenworkingwithReactfortheWeb,wetypicallyuseseparatestylesheetfiles,which
maybewritteninCSS,SASS,orLESS.ReactNativetakesaradicallydifferentapproach,
bringingstylesentirelyintotheworldofJavaScriptandforcingyoutolinkstyleobjects
explicitlytocomponents.Needlesstosay,thisapproachtendstoprovokestrongreactions,
asitrepresentsasignificantdeparturefromCSS-basedstylingnorms.


TounderstandthedesignofReactNative’sstyles,firstweneedtoconsidersomeofthe
headachesassociatedwithtraditionalCSSstylesheets.1CSShasanumberofproblems.
AllCSSrulesandclassnamesareglobalinscope,meaningthatstylingonecomponent
caneasilybreakanotherifyou’renotcareful.Forinstance,ifyouincludethepopular
TwitterBootstraplibrary,youwillintroduceover600newglobalvariables.BecauseCSS
isnotexplicitlyconnectedtotheHTMLelementsitstyles,deadcodeeliminationis


difficult,anditcanbenontrivialtodeterminewhichstyleswillapplytoagivenelement.


LanguageslikeSASSandLESSattempttoworkaroundsomeofCSS’suglierparts,but
manyofthesamefundamentalproblemsremain.WithReact,wehavetheopportunityto
keepthedesirablepartsofCSS,butalsothefreedomforsignificantdivergence.React
NativeimplementsasubsetoftheavailableCSSstyles,focusingonkeepingthestyling
APInarrowyetstillhighlyexpressive.Positioningisdramaticallydifferent,aswe’llsee
laterinthischapter.Additionally,ReactNativedoesnotsupportpseudoclasses,



animations,orselectors.Afulllistofsupportedpropertiescanbefoundinthedocs.


<i>Insteadofstylesheets,inReactNativeweworkwithJavaScript-basedstyleobjects.One</i>
ofReact’sgreateststrengthsisthatitforcesyoutokeepyourJavaScriptcode—your
components—modular.BybringingstylesintotherealmofJavaScript,ReactNative
pushesustowritemodularstyles,too.


</div>
<span class='text_page_counter'>(130)</span><div class='page_container' data-page=130>

<b>InlineStyles</b>



Inlinestylesarethesimplestway,syntactically,tostyleacomponentinReactNative,
<i>thoughtheyarenotusuallythebestway.Asyoucanseein</i>Example5-1,thesyntaxfor
inlinestylesinReactNativeisthesameasforReactforthebrowser.


<i>Example5-1.Usinginlinestyles</i>


<Text>


Thequick<Textstyle={{fontStyle:"italic"}}>brown</Text>fox


jumpedoverthelazy<Textstyle={{fontWeight:"bold"}}>dog</Text>.
</Text>


Inlinestyleshavesomeadvantages.They’requickanddirty,allowingyoutorapidly
experiment.


</div>
<span class='text_page_counter'>(131)</span><div class='page_container' data-page=131>

<b>StylingwithObjects</b>



Ifyoutakealookattheinlinestylesyntax,youwillseethatit’ssimplypassinganobject
tothestyleattribute.There’snoneedtocreatethestyleobjectintherendercall,though;
instead,youcanseparateitout,asshowninExample5-2.



<i>Example5-2.StyleattributewillacceptaJavaScriptobject</i>


<b>var</b>italic={


fontStyle:'italic'


};


<b>var</b>bold={


fontWeight:'bold'


};


...


render(){
return(
<Text>


Thequick<Textstyle={italic}>brown</Text>fox


jumpedoverthelazy<Textstyle={bold}>dog</Text>.
</Text>


);
}


<i>PanDemo.js,from</i>Example4-7,givesusagoodexampleofausecaseinwhichthe


immutabilityprovidedbyStylesheet.Createisahindranceratherthanahelp.Recall
thatwewantedtoupdatethelocationofacirclebasedonmovement—inotherwords,
eachtimewereceivedanupdatefromthePanResponder,weneededtoupdatestateas
wellaschangethestylesonthecircle.Inthiscircumstance,wedon’twantimmutabilityat
all,atleastnotforthestylecontrollingthecircle’slocation.


</div>
<span class='text_page_counter'>(132)</span><div class='page_container' data-page=132>

<b>UsingStylesheet.Create</b>



YouwillnoticethatalmostalloftheReactNativeexamplecodemakesuseof


StyleSheet.create.UsingStyleSheet.createisstrictlyoptional,butingeneralyou’ll
wanttouseit.Here’swhatthedocshavetosay:


StyleSheet.createconstructisoptionalbutprovidessomekeyadvantages.Itensuresthat
thevaluesareimmutableandopaquebytransformingthemintoplainnumbersthat
referenceaninternaltable.Byputtingitattheendofthefile,youalsoensurethatthey
areonlycreatedoncefortheapplicationandnotoneveryrender.


Inotherwords,StyleSheet.createisreallyjustabitofsyntacticsugardesignedto
protectyou.Useit!Thevastmajorityofthetime,theimmutabilityprovidedby
StyleSheet.createishelpful.Italsogivesyoutheabilitytodopropvalidationvia


</div>
<span class='text_page_counter'>(133)</span><div class='page_container' data-page=133>

<b>StyleConcatenation</b>


Whathappensifyouwanttocombinetwoormorestyles?
Recallthatearlierwesaidthatweshouldpreferreusingstyledcomponentsoverstyles.
That’strue,butsometimesstylereuseisalsouseful.Forinstance,ifyouhaveabutton
styleandanaccentTextstyle,youmaywanttocombinethemtocreateanAccentButton
component.
Ifthestyleslooklikethis:
varstyles=Stylesheet.create({

button:{
borderRadius:'8px',
backgroundColor:'#99CCFF'
},
accentText:{
fontSize:18,
fontWeight:'bold'
}
});
<i>Thenyoucancreateacomponentthathasbothofthosestylesappliedthroughsimple</i>
concatenation(Example5-3).


<i>Example5-3.Styleattributealsoacceptsanarrayofobjects</i>


<b>var</b>AccentButton=React.createClass({
render:function(){


return(


<Textstyle={[styles.button,styles.accentText]}>
{this.props.children}


</Text>
);


}
});


Asyoucansee,thestyleattributecantakeanarrayofstyleobjects.Youcanalsoadd
inlinestyleshere,ifyouwant(Example5-4).



<i>Example5-4.Youcanmixstyleobjectsandinlinestyles</i>


<b>var</b>AccentButton=React.createClass({
render:function(){


return(


<Textstyle={[styles.button,styles.accentText,{color:'#FFFFFF'}]}>
{this.props.children}


</Text>
);


}
});


Inthecaseofaconflict,suchaswhentwoobjectsbothspecifythesameproperty,React
Nativewillresolvetheconflictforyou.Therightmostelementsinthestylearraytake
precedence,andfalsyvalues(false,null,undefined)areignored.


Youcanleveragethispatterntoapplyconditionalstyles.Forexample,ifwehada


<Button>componentandwantedtoapplyextrastylerulesifit’sbeingtouched,wecould


usethecodeshowninExample5-5.


<i>Example5-5.Usingconditionalstyles</i>


</div>
<span class='text_page_counter'>(134)</span><div class='page_container' data-page=134>

Thisshortcutcanhelpyoukeepyourrenderinglogicconcise.



</div>
<span class='text_page_counter'>(135)</span><div class='page_container' data-page=135>

<b>OrganizationandInheritance</b>



</div>
<span class='text_page_counter'>(136)</span><div class='page_container' data-page=136>

<b>ExportingStyleObjects</b>


Asyourstylesgrowmorecomplex,youwillwanttokeepthemseparatefromyour
components’JavaScriptfiles.Onecommonapproachistohaveaseparatefolderforeach
component.Ifyouhaveacomponentnamed<ComponentName>,youwouldcreateafolder
<i>namedComponentName/andstructureitlikeso:</i>
-ComponentName
|-index.js
|-styles.js


<i>Withinstyles.js,youcreateastylesheet,andexportit(</i>Example5-6).


<i>Example5-6.ExportingstylesfromaJavaScriptfile</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>


StyleSheet,
}=React;


<b>var</b>styles=Stylesheet.create({
text:{


color:'#FF00FF',
fontSize:16


},


bold:{


fontWeight:'bold'


}
});


module.exports=styles;


<i>Withinindex.js,wecanimportourstyleslikeso:</i>


<b>var</b>styles=require('./styles.js');


Thenwecanusetheminourcomponent(Example5-7).


<i>Example5-7.ImportingstylesfromanexternalJavaScriptfile</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var</b>styles=require('./styles.js');
<b>var{</b>


View,
Text,
StyleSheet


}=React;


<b>var</b>ComponentName=React.createClass({
render:function(){



return(


<Textstyle={[styles.text,styles.bold]}>
Hello,world


</Text>
);


</div>
<span class='text_page_counter'>(137)</span><div class='page_container' data-page=137>

<b>PassingStylesasProps</b>



Youcanalsopassstylesasproperties.ThepropTypeView.propTypes.styleensuresthat
onlyvalidstylesarepassedasprops.


Youcanusethispatterntocreateextensiblecomponents,whichcanbemoreeffectively
controlledandstyledbytheirparents.Forexample,acomponentmighttakeinanoptional
styleprop(Example5-8).


<i>Example5-8.Componentscanreceivestyleobjectsviaprops</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>


View,
Text


}=React;


<b>var</b>CustomizableText=React.createClass({


propTypes:{


style:Text.propTypes.Style


},
getDefaultProps:function(){
return{
style:{}
};
},
render:function(){
return(


<Textstyle={[myStyles.text,this.props.style]}>
Hello,world


</Text>
);


}
});


</div>
<span class='text_page_counter'>(138)</span><div class='page_container' data-page=138>

<b>ReusingandSharingStyles</b>



Wetypicallyprefertoreusestyledcomponents,ratherthanreusingstyles,butthereare
clearlysomeinstancesinwhichyouwillwanttosharestylesbetweencomponents.Inthis
case,acommonpatternistoorganizeyourprojectroughlylikeso:


-js



|-components
|-Button
|-index.js
|-styles.js
|-styles


|-styles.js
|-colors.js
|-fonts.js


Byhavingseparatedirectoriesforcomponentsandforstyles,youcankeeptheintended
useofeachfileclearbasedoncontext.Acomponent’sfoldershouldcontainitsReact
class,aswellasanycomponent-specificfiles.Sharedstylesshouldbekeptoutof
componentfolders.Sharedstylesmayincludethingssuchasyourpalette,fonts,
standardizedmarginsandpadding,andsoon.


<i>styles/styles.jsrequirestheothersharedstylesfiles,andexposesthem;thenyour</i>


<i>componentscanrequirestyles.jsandusesharedfilesasneeded.Or,youmaypreferto</i>
<i>havecomponentsrequirespecificstylesheetsfromthestyles/directoryinstead.</i>


</div>
<span class='text_page_counter'>(139)</span><div class='page_container' data-page=139>

<b>PositioningandDesigningLayouts</b>



</div>
<span class='text_page_counter'>(140)</span><div class='page_container' data-page=140>

<b>LayoutswithFlexbox</b>



FlexboxisaCSS3layoutmode.Unlikeexistinglayoutmodessuchasblockandinline,
flexboxgivesusadirection-agnosticwayofconstructinglayouts.(That’sright:finally,
verticallycenteringiseasy!)ReactNativeleansheavilyonflexbox.Ifyouwanttoread
moreaboutthegeneralspecification,theMDNdocumentationisagoodplacetostart.



WithReactNative,thefollowingflexboxpropsareavailable:
flex
flexDirection
flexWrap
alignSelf
alignItems
Additionally,theserelatedvaluesimpactlayout:
height
width
margin
border
padding
IfyouhaveworkedwithflexboxontheWebbefore,therewon’tbemanysurpriseshere.
BecauseflexboxissoimportanttoconstructinglayoutsinReactNative,though,we’ll
spendsometimenowexploringhowitworks.
Thebasicideabehindflexboxisthatyoushouldbeabletocreatepredictablystructured
layoutsevengivendynamicallysizedelements.Becausewe’redesigningformobile,and
needtoaccommodatemultiplescreensizesandorientations,thisisausefulfeature.
We’llstartwithaparent<View>,andsomechildren:


<Viewstyle={styles.parent}>


<Textstyle={styles.child}>ChildOne</Text>
<Textstyle={styles.child}>ChildTwo</Text>
<Textstyle={styles.child}>ChildThree</Text>
</View>


Tostart,we’veappliedsomebasicstylestotheviews,buthaven’ttouchedthepositioning
yet:



</div>
<span class='text_page_counter'>(141)</span><div class='page_container' data-page=141>

backgroundColor:'#F5FCFF',
borderColor:'#0099AA',
borderWidth:5,


marginTop:30


},
child:{


borderColor:'#AA0099',
borderWidth:2,


textAlign:'center',
fontSize:24,


}
});


</div>
<span class='text_page_counter'>(142)</span><div class='page_container' data-page=142></div>
<span class='text_page_counter'>(143)</span><div class='page_container' data-page=143>

<i>Figure5-1.Thelayoutbeforeweaddflexproperties</i>


Next,wewillsetflexonboththeparentandthechild.Bysettingtheflexproperty,we
areexplicitlyoptingintoflexboxbehavior.flextakesanumber.Thisnumberdetermines
therelativeweighteachchildgets;bysettingitto1foreachchild,weweightthem


equally.


WealsosetflexDirection:'column'sothatthechildrenarelaidoutvertically.Ifwe
switchthistoflexDirection:'row',thechildrenwillbelaidouthorizontallyinstead.
ThesechangestothestylescanbeseeninExample5-9.Figure5-2illustratesthe



</div>
<span class='text_page_counter'>(144)</span><div class='page_container' data-page=144>

<i>Figure5-2.SettingbasicflexpropertiesandflexDirection;settingflexDirectiontocolumn(left)andsettingflexDirection</i>
<i>torow(right)</i>


<i>Example5-9.ChangingtheflexandflexDirectionproperties</i>


<b>var</b>styles=StyleSheet.create({
parent:{


flex:1,


flexDirection:'column',
backgroundColor:'#F5FCFF',
borderColor:'#0099AA',
borderWidth:5,


marginTop:30


},
child:{
flex:1,


borderColor:'#AA0099',
borderWidth:2,


textAlign:'center',
fontSize:24,


}
});



</div>
<span class='text_page_counter'>(145)</span><div class='page_container' data-page=145>

Then,thealignItemsvaluedetermineswheretheyarepositionedalongthecross-axis.
Thecross-axisistheaxisorthogonaltotheflexDirection.Inthiscase,thecrossaxisis
vertical.flex-startplacesthechildrenatthetop,centercentersthem,andflex-end
placesthematthebottom.


Let’sseewhathappenswhenwesetalignItems(theresultisshowninFigure5-3):


<b>var</b>styles=StyleSheet.create({
parent:{


flex:1,


flexDirection:'row',
alignItems:'flex-start',
backgroundColor:'#F5FCFF',
borderColor:'#0099AA',
borderWidth:5,


marginTop:30


},
child:{
flex:1,


borderColor:'#AA0099',
borderWidth:2,


textAlign:'center',
fontSize:24,



}
});


</div>
<span class='text_page_counter'>(146)</span><div class='page_container' data-page=146>

<b>UsingAbsolutePositioning</b>



Inadditiontoflexbox,ReactNativesupportsabsolutepositioning.Itworksmuchasit
doesontheWeb.Youcanenableitbysettingthepositionproperty:


<b>position:</b>absolute


Then,youcancontrolthecomponent’spositioningwiththefamiliarpropertiesofleft,


right,top,andbottom.


Anabsolutelypositionedchildwillapplythesecoordinatesrelativetoitsparent’sposition,
soyoucanlayoutaparentelementusingflexboxandthenuseabsolutepositionfora
childwithinit.


Therearesomelimitationstothis.Wedon’thavez-index,forinstance,solayeringviews
ontopofeachotherisabitcomplicated.Thelastviewinastacktypicallytakes


precedence.


Absolutepositioningcanbeveryuseful.Forinstance,ifyouwanttocreateacontainer
viewthatsitsbelowthephone’sstatusbar,absolutepositioningmakesthiseasy:


container:{


position:'absolute',
top:30,



left:0,
right:0,
bottom:0


</div>
<span class='text_page_counter'>(147)</span><div class='page_container' data-page=147>

<b>PuttingItTogether</b>



</div>
<span class='text_page_counter'>(148)</span><div class='page_container' data-page=148></div>
<span class='text_page_counter'>(149)</span><div class='page_container' data-page=149>

<i>Figure5-4.We’lluseflexboxtoconstructthislayout</i>


Howshouldwegoaboutconstructingthiskindoflayout?


Tostartwith,wecreateaparentstyletoactasthecontainer.Wewilluseabsolute
positioningontheparent,becauseit’smostappropriate:wewantittofillallavailable
space,exceptwitha30-pixeloffsetatthetop,duetothestatusbaratthetopofthescreen.
We’llalsosetitsflexDirectiontocolumn:


<b>parent:{</b>


flexDirection:'column',
position:'absolute',
top:30,


left:0,
right:0,
bottom:0


}


</div>
<span class='text_page_counter'>(150)</span><div class='page_container' data-page=150></div>
<span class='text_page_counter'>(151)</span><div class='page_container' data-page=151>

<i>Figure5-5.Theorderinwhichwe’llstylethesections</i>



Westartbycuttingthelayoutintoatopandbottomblock:


<Viewstyle={styles.parent}>
<Viewstyle={styles.topBlock}>
</View>


<Viewstyle={styles.bottomBlock}>
</View>


</View>


Thenweaddinthenextlayer.Thisincludesbotha“leftcolumn”and“bottomright”
sector,aswellastheactual<View>componentsforcellsthree,four,andfive:


<Viewstyle={styles.parent}>
<Viewstyle={styles.topBlock}>
<Viewstyle={styles.leftCol}>
</View>


<Viewstyle={[styles.cellThree,styles.base]}/>
</View>


<Viewstyle={styles.bottomBlock}>


<Viewstyle={[styles.cellFour,styles.base]}/>
<Viewstyle={[styles.cellFive,styles.base]}/>
<Viewstyle={styles.bottomRight}>


</View>
</View>


</View>


Thefinalmarkupcontainsallsevencells.Example5-10showsthefullcomponent.


<i>Example5-10.Styles/Mondrian/index.js</i>
'usestrict';


<b>var</b>React=require('react-native');
<b>var{</b>


AppRegistry,
StyleSheet,
Text,
View,
}=React;


<b>var</b>styles=require('./style');
<b>var</b>Mondrian=React.createClass({
render:function(){


return(


<Viewstyle={styles.parent}>
<Viewstyle={styles.topBlock}>
<Viewstyle={styles.leftCol}>


<Viewstyle={[styles.cellOne,styles.base]}/>
<Viewstyle={[styles.base,styles.cellTwo]}/>
</View>



<Viewstyle={[styles.cellThree,styles.base]}/>
</View>


<Viewstyle={styles.bottomBlock}>


<Viewstyle={[styles.cellFour,styles.base]}/>
<Viewstyle={[styles.cellFive,styles.base]}/>
<Viewstyle={styles.bottomRight}>


<Viewstyle={[styles.cellSix,styles.base]}/>
<Viewstyle={[styles.cellSeven,styles.base]}/>
</View>


</View>
</View>
);


}
});


</div>
<span class='text_page_counter'>(152)</span><div class='page_container' data-page=152>

Nowlet’saddthestylesthatmakeitwork(Example5-11).


<i>Example5-11.Styles/Mondrian/style.js</i>


<b>var</b>React=require('react-native');


<b>var{</b>StyleSheet}=React;


<b>var</b>styles=StyleSheet.create({
parent:{



flexDirection:'column',
position:'absolute',
top:30,


left:0,
right:0,
bottom:0


},
base:{


borderColor:'#000000',
borderWidth:5


},


topBlock:{


flexDirection:'row',
flex:5


},


leftCol:{
flex:2


},


bottomBlock:{


flex:2,


flexDirection:'row'


},


bottomRight:{


flexDirection:'column',
flex:2


},


cellOne:{
flex:1,


borderBottomWidth:15


},


cellTwo:{
flex:3


},


cellThree:{


backgroundColor:'#FF0000',
flex:5



},


cellFour:{
flex:3,


backgroundColor:'#0000FF'


},


cellFive:{
flex:6


},


cellSix:{
flex:1


},


cellSeven:{
flex:1,


backgroundColor:'#FFFF00'


}
});


</div>
<span class='text_page_counter'>(153)</span><div class='page_container' data-page=153>

<b>Summary</b>



Inthischapter,welookedathowstylesworkinReactNative.Whileinmanywaysstyling


issimilartohowCSSworksontheWeb,ReactNativeintroducesadifferentstructureand
approachtostyling.There’splentyofnewmaterialtodigesthere!Atthispoint,you


shouldbeabletousestyleseffectivelytocreatethemobileUIsyouneedwithReact
Native.Andbestofall,experimentingwithstylesiseasy:beingabletohit“reload”inthe
simulatorgrantsusatightfeedbackloop.(It’sworthnotingthatwithtraditionalmobile
development,editingastylewouldtypicallyrequirerebuildingyourapplication.Yikes.)


Ifyouwantmorepracticewithstyles,trygoingbacktotheBestSellersorWeather
applications,andadjustingtheirstylingandlayouts.Aswebuildmoresample
applicationsinfuturechapters,you’llhaveplentyofmaterialtopracticewith,too!


</div>
<span class='text_page_counter'>(154)</span><div class='page_container' data-page=154></div>
<span class='text_page_counter'>(155)</span><div class='page_container' data-page=155>

<b>Chapter6.PlatformAPIs</b>



Whenbuildingmobileapplications,youwillnaturallywanttotakeadvantageofthehost
platform’sspecificAPIs.ReactNativemakesiteasytoaccessthingslikethephone’s
cameraroll,location,andpersistentstorage.TheseplatformAPIsaremadeavailableto
ReactNativethroughincludedmodules,whichprovideuswitheasy-to-useasynchronous
JavaScriptinterfacestothesefunctions.


<i>ReactNativedoesnotwrapallofitshostplatform’sfunctionalitybydefault;some</i>


platformAPIswillrequireyoutoeitherwriteyourownmodules,orusemoduleswritten
byothersintheReactNativecommunity.WewillcoverthatprocessinChapter7.The


docsarethebestplacetocheckifanAPIissupported.


ThischaptercoverssomeoftheavailableplatformAPIs.Forourexample,we’llmake
somemodificationstotheWeatherapplicationfromearlier.We’lladdgeolocationtothe
app,sothatitdetectstheuser’slocationautomatically.Wewillalsoadd“memory”tothe


app,soitwillrememberyourpreviouslysearchedlocations.Finally,we’llusethecamera
rolltochangethebackgroundimagetooneoftheuser’sphotos.


</div>
<span class='text_page_counter'>(156)</span><div class='page_container' data-page=156></div>
<span class='text_page_counter'>(157)</span><div class='page_container' data-page=157>

<b>IOSANDANDROIDCOMPATIBILITY</b>


</div>
<span class='text_page_counter'>(158)</span><div class='page_container' data-page=158>

<b>UsingGeolocation</b>



Formobileapplications,knowingtheuser’slocationisoftencritical.Itallowsyouto
servetheusercontextuallyrelevantinformation.Manymobileapplicationsmake
extensiveuseofthisdata.



Happily,ReactNativehasbuilt-insupportforgeolocation.Thisisprovidedasaplatform-agnostic“polyfill.”ItreturnsdatabasedontheMDNGeolocationAPIwebspecification.


</div>
<span class='text_page_counter'>(159)</span><div class='page_container' data-page=159></div>
<span class='text_page_counter'>(160)</span><div class='page_container' data-page=160>

<b>GEOLOCATIONISCURRENTLYIOS-ONLY</b>


</div>
<span class='text_page_counter'>(161)</span><div class='page_container' data-page=161>

<b>GettingtheUser’sLocation</b>



UsingtheGeolocationAPItogetauser’slocationisabreeze.AsshowninExample6-1,
weneedtomakeacalltonavigator.geolocation.


<i>Example6-1.Gettingtheuser’slocationwithanavigator.geolocationcall</i>


navigator.geolocation.getCurrentPosition(
(position)=>{


console.log(position);
},


(error)=>{alert(error.message)},



{enableHighAccuracy:true,timeout:20000,maximumAge:1000}
);
InconformancetotheGeolocationspecification,wedon’timportthisAPIasaseparate
module;it’ssimplyavailableforouruse.
ThegetCurrentPositioncalltakesthreearguments:asuccesscallback,anerrorcallback,
andasetofgeoOptions.Onlythesuccesscallbackisrequired.
Thepositionobjectpassedtothesuccesscallbackwillcontaincoordinates,aswellasa
timestamp.Example6-2showstheformatandpossiblevalues.


<i>Example6-2.ShapeoftheresponsereturnedfromagetCurrentPositioncall</i>


{


coords:{
speed:-1,


longitude:-122.03031802,
latitude:37.33259551999998,
accuracy:500,


heading:-1,
altitude:0,


altitudeAccuracy:-1


},


timestamp:459780747046.605



}


geoOptionsshouldbeanobject,whichoptionallyincludesthekeystimoeut,


</div>
<span class='text_page_counter'>(162)</span><div class='page_container' data-page=162>

<b>HandlingPermissions</b>



Locationdataissensitiveinformation,andthereforewillnotbeaccessibletoyour
applicationbydefault.Yourapplicationshouldbeabletohandlepermissionsbeing
acceptedorrejected.


Mostmobileplatformshavesomenotionoflocationpermissions.Ausermayopttoblock

LocationServicesentirelyoniOS,forinstance,ortheymaymanagepermissionsonaper-appbasis.Iftheuserdeniesyourapplicationaccess,thecancellationcallbackyoupassto
getCurrentPositionwillbeinvoked.


It’simportanttonotethatlocationpermissionscanberevokedatessentiallyanypointin
time.Yourapplicationshouldalwaysbepreparedforageolocationcalltofail.


Thefirsttimeyourapplicationattemptstoaccesstheuser’slocation,theuserwillbe
presentedwithapermissionsdialogliketheoneshowninFigure6-1.


<i>Figure6-1.Locationrequest</i>


Whilethisdialogisactive,neithercallbackwillfire;oncetheyselectanoption,the
appropriatecallbackwillbeinvoked.Thissettingwillpersistforyourapplication,sothe
nexttime,suchacheckwon’tbenecessary.


</div>
<span class='text_page_counter'>(163)</span><div class='page_container' data-page=163>

<b>TestingGeolocationIntheiOSSimulator</b>



Chancesareyou’llbedoingmostofyourtestinganddevelopmentfromwithina



simulator,orattheveryleast,atyourdesk.Howcanyoutesthowyourappwillbehaveat
differentlocations?


</div>
<span class='text_page_counter'>(164)</span><div class='page_container' data-page=164>

<i>Figure6-2.Pickingalocation</i>


</div>
<span class='text_page_counter'>(165)</span><div class='page_container' data-page=165>

<b>WatchingtheUser’sLocation</b>



Youcanalsosetawatchontheuser’slocation,andreceiveupdateswheneveritchanges.
Thiscanbeusedtotrackauser’slocationovertime,orjusttoensurethatyourapp


receivesthemostup-to-dateposition:


<b>this.</b>watchID=navigator.geolocation.watchPosition((position)=>{


this.setState({position:position});
});


Notethatyou’llwanttoclearthewatchwhenyourcomponentunmountsaswell:


componentWillUnmount:function(){


</div>
<span class='text_page_counter'>(166)</span><div class='page_container' data-page=166>

<b>Limitations</b>



BecausegeolocationisbasedontheMDNspecification,itleavesoutmoreadvanced
location-basedfeatures.Forexample,iOSprovidesaGeofencingAPI,whichallowsyour
applicationtoreceivenotificationswhentheuserentersorleavesadesignated


geographicalregion(thegeofence).ReactNativecurrentlydoesnotexposethisAPI.



</div>
<span class='text_page_counter'>(167)</span><div class='page_container' data-page=167>

<b>UpdatingtheWeatherApplication</b>



TheSmarterWeatherapplicationisanupdatedversionoftheWeatherapplication,which
nowmakesuseoftheGeolocationAPI.YoucanseethesechangesinFigure6-3.


</div>
<span class='text_page_counter'>(168)</span><div class='page_container' data-page=168></div>
<span class='text_page_counter'>(169)</span><div class='page_container' data-page=169>

<i>Figure6-3.Displayingforecastbasedontheuser’scurrentlocation</i>


<i>Example6-3.SmarterWeather/LocationButton/index.js:whenpressed,thebuttongetsthe</i>
<i>user’slocation</i>


<b>var</b>React=require('react-native');
<b>var</b>styles=require('./style.js');
<b>var</b>Button=require('./../Button');
<b>var</b>LocationButton=React.createClass({
propTypes:{


onGetCoords:React.PropTypes.func.isRequired


},


_onPress:function(){


navigator.geolocation.getCurrentPosition(
(initialPosition)=>{


this.props.onGetCoords(initialPosition.coords.latitude,
initialPosition.coords.longitude);


},



(error)=>{alert(error.message)},


{enableHighAccuracy:true,timeout:20000,maximumAge:1000}
);


},


render:function(){
return(


<Buttonlabel="UseCurrentLocation"


style={styles.locationButton}
onPress={this._onPress}/>
);


}
});


module.exports=LocationButton;


TheButtoncomponentusedbyLocationButtonisincludedattheendofthischapter;it
simplywrapsa<Text>componentinanappropriate<TouchableHighlight>withsome
basicstyling.


<i>We’vealsohadtoupdatethemainweather_project.jsfiletoaccommodatetwokindsof</i>
queries(Example6-4).Happily,theOpenWeatherMapAPIallowsustoquerybylatitude
andlongitudeaswellaszipcode.


<i>Example6-4.Adding_getForecastForCoordsand_getForecastForZipfunctions</i>



<b>var</b>WEATHER_API_KEY='bbeb34ebf60ad50f7893e7440a1e2b0b';


<b>var</b>API_STEM=' />...


_getForecastForZip:function(zip){
this._getForecast(


`${API_STEM}q=${zip}&units=imperial&APPID=${WEATHER_API_KEY}`);
},


_getForecastForCoords:function(lat,lon){
this._getForecast(


`${API_STEM}lat=${lat}&lon=${lon}&units=imperial&APPID=${WEATHER_API_KEY}`);
},


_getForecast:function(url,cb){
fetch(url)


.then((response)=>response.json())
.then((responseJSON)=>{


console.log(responseJSON);
this.setState({


forecast:{


main:responseJSON.weather[0].main,



</div>
<span class='text_page_counter'>(170)</span><div class='page_container' data-page=170>

temp:responseJSON.main.temp


}
});
})


.catch((error)=>{
console.warn(error);
});


}


ThenweincludetheLocationButtoninthemainviewwith_getForecastForCoordsas
thecallback:


<LocationButtononGetCoords={this._getForecastForCoords}/>


I’veomittedtherelevantstyleupdatesandsoon,asthefullyupdatedapplicationcode
willbeincludedattheendofthischapter.


</div>
<span class='text_page_counter'>(171)</span><div class='page_container' data-page=171>

<b>AccessingtheUser’sImagesandCamera</b>



Havingaccesstoaphone’slocalimages,aswellasthecamera,isanothercriticalpartof
manymobileapplications.Inthissection,we’llexploreyouroptionsforinteractingwith
users’imagedataaswellasthecamera.


</div>
<span class='text_page_counter'>(172)</span><div class='page_container' data-page=172>

<b>TheCameraRollModule</b>



</div>
<span class='text_page_counter'>(173)</span><div class='page_container' data-page=173></div>
<span class='text_page_counter'>(174)</span><div class='page_container' data-page=174>

<b>CAMERAROLLISCURRENTLYIOS-ONLY</b>



TheCameraRollmodulewillbesupportedonAndroidsoon,butfornowit’siOS-only.


InteractingwiththeCameraRoll,initsmostbasicform,isnottoocomplicated.Firstwe
requirethemodule,asperusual:


<b>var</b>React=require('react-native');


<b>var{</b>CameraRoll}=React;


Then,wemakeuseofthemoduletofetchinformationabouttheuser’sphotos,asshown
inExample6-5.


<i>Example6-5.BasicusageofCameraRoll.getPhotos</i>


CameraRoll.getPhotos(
{first:1},


(data)=>{


console.log(data);
},


(error)=>{


console.warn(error);
});


WemakeacalltogetPhotoswiththeappropriatequery,anditreturnssomedatarelated
totheCameraRollimages.



InSmarterWeather,let’sreplacethetop-level<Image>componentwithanewcomponent,
PhotoBackdrop(Example6-6).Fornow,PhotoBackdropsimplypullsthemostrecent
photofromtheuser’sCameraRoll.


<i>Example6-6.SmarterWeather/PhotoBackdrop/camera_roll_example.js</i>


<b>var</b>React=require('react-native');


<b>var{</b>Image,CameraRoll}=React;


<b>var</b>styles=require('./style.js');
<b>var</b>PhotoBackdrop=React.createClass({
getInitialState(){
return{
photoSource:null
}
},
componentDidMount(){
CameraRoll.getPhotos(
{first:5},


(data)=>{
this.setState({


photoSource:{uri:data.edges[3].node.image.uri}
})},


(error)=>{


console.warn(error);


});


},


render(){
return(
<Image


style={styles.backdrop}


source={this.state.photoSource}
resizeMode='cover'>


{this.props.children}
</Image>


);
}
});


</div>
<span class='text_page_counter'>(175)</span><div class='page_container' data-page=175></div>
<span class='text_page_counter'>(176)</span><div class='page_container' data-page=176>

<b>RequestingImageswithGetPhotoParams</b>



ThegetPhotoParamsobjectcantakeavarietyofoptions,whichareoddlynotincludedin
thewebdocumentation.WecantakealookattheReactNativesourcecodetoseewhich
optionsareavailabletous:


<i>first</i>


number,thenumberofphotoswantedinreverseorderofthephotoapplication(i.e.,
mostrecentfirstforSavedPhotos)



<i>after</i>


string,acursorthatmatchespage_info{end_cursor}returnedfromapreviouscall
togetPhotos


<i>groupTypes</i>


string,specifieswhichgrouptousetofilterresults.Maybe<i>Album</i>,<i>All</i>,<i>Event</i>,etc.;
fulllistofGroupTypesarespecifiedinthesource


<i>groupName</i>


string,specifiesafilterongroupnames,suchas<i>RecentPhotos</i>oranalbumtitle


<i>assetType</i>


oneof<i>All</i>,<i>Photos</i>,or<i>Videos</i>,specifiesafilteronassettype


<i>mimeTypes</i>


<i>arrayofstrings,filtersbasedonmimetype(suchasimage/jpeg)</i>


InourbasicinvocationofgetPhotosinExample6-5,ourgetPhotoParamsobjectwas
quitesimple:


{first:1}


</div>
<span class='text_page_counter'>(177)</span><div class='page_container' data-page=177>

<b>RenderinganImagefromtheCameraRoll</b>




Howdowerenderanimagewe’vereceivedfromthecameraroll?Let’stakealookatthat
successcallback:


(data)=>{
this.setState({


photoSource:{uri:data.edges[0].node.image.uri}
})},


Thestructureofthedataobjectisnotimmediatelyapparent,soyou’lllikelywanttouse
thedebuggertoinspecttheobject.Eachoftheobjectsindata.edgeshasanodethat
representsaphoto;fromthere,youcangettheURIoftheactualasset.


Youmayrecallthatan<Image>componentcantakeaURIasitssourceproperty.So,we
canrenderanimageobtainedfromthecamerarollbysettingthesourceproperty


appropriately:


<Imagesource={this.state.photoSource}/>


</div>
<span class='text_page_counter'>(178)</span><div class='page_container' data-page=178></div>
<span class='text_page_counter'>(179)</span><div class='page_container' data-page=179></div>
<span class='text_page_counter'>(180)</span><div class='page_container' data-page=180>

<b>DisplayingaListofPhotos</b>



Inmanyapps,wegivetheusertheabilitytoselectaphoto.Howdoyourenderthatphoto
selectionscreen?


</div>
<span class='text_page_counter'>(181)</span><div class='page_container' data-page=181>

<i>Figure6-5.PhotoselectionscreensintheTumblr(left)andTwitter(right)iOSapplications</i>


</div>
<span class='text_page_counter'>(182)</span><div class='page_container' data-page=182></div>
<span class='text_page_counter'>(183)</span><div class='page_container' data-page=183>

<i>Figure6-6.Defaultdialog</i>


So,youcaneitherusethebuilt-inelementforthis,orrollyourown.Applicationsoften


buildcustomsolutionsinordertoprovideadditionalfunctionalityoverthestandard
interface.TheUIExplorerapplicationgivesusaverybasicexampleofhowtousethe


CameraRolltocreateasimplecustomviewoftheuser’sphotolibrary,shownin


</div>
<span class='text_page_counter'>(184)</span><div class='page_container' data-page=184></div>
<span class='text_page_counter'>(185)</span><div class='page_container' data-page=185>

<i>Figure6-7.TheCameraRollexamplefromtheUIExplorerapplication</i>


It’slittlemorethantheCameraRollinteractionswesawearlier,coupedwitha


<ListView>.Youcouldusethisapproachtodevelopacross-platformimageselection


componentforbothAndroidandiOS.


</div>
<span class='text_page_counter'>(186)</span><div class='page_container' data-page=186></div>
<span class='text_page_counter'>(187)</span><div class='page_container' data-page=187>

<b>ANDROIDSUPPORTFORPHOTOSELECTION</b>


Currently,ReactNativeprovidestheImagePickerIOSAPIforselectingphotosoraccessingthecameraon
iOS,butthereisn’tanequivalentforAndroidyet.Checkthedocumentationforthemostup-to-date
information.


YoucanimporttheImagePickerIOSmoduleintheusualway:


<b>var{</b>ImagePickerIOS}=React;


Then,usingitissimple.WecanqueryImagePickerIOStoseeifweareabletousethe
cameraorrecordvideos(Example6-7).


<i>Example6-7.Checkingifwemayaccessthecameraorrecordvideosusing</i>
<i>ImagePickerIOS</i>


ImagePickerIOS.canUseCamera((result)=>{


console.log(result);<i>//boolean</i>


});


ImagePickerIOS.canRecordVideos((result)=>{
console.log(result);<i>//boolean</i>


});


Then,totriggerthephotoselectiondialog,wecallopenSelectDialog,furnishingitwith
someoptionsaswellascallbacksforsuccessfulphotoselection,andusercancellation
(Example6-8).


<i>Example6-8.TriggeringthephotoselectiondialogusingImagePickerIOS</i>


ImagePickerIOS.openSelectDialog(
{


showImages:true,
showVideos:false,
},


(data)=>{
this.setState({


photoSource:{uri:data}
});


},
()=>{



console.log('Usercanceledtheaction');
});


</div>
<span class='text_page_counter'>(188)</span><div class='page_container' data-page=188></div>
<span class='text_page_counter'>(189)</span><div class='page_container' data-page=189>

<i>Figure6-8.iOSselectiondialog</i>


</div>
<span class='text_page_counter'>(190)</span><div class='page_container' data-page=190>

<b>UploadinganImagetoaServer</b>



Whatifyouwanttouploadaphotosomewhere?ReactNativeshipswithbuilt-inimage
uploadingfunctionalityintheXHRmodule.TheUIExplorerexampledemonstratesone
approach:


<b>var</b>formdata=newFormData();
...


formdata.append('image',{...this.state.randomPhoto,name:'image.jpg'});
...


xhr.send(formdata);


XHRisshortforXMLHttpRequest.ReactNativeimplementstheXHRAPIontopofthe
iOSnetworkingAPIs.Similartogeolocation,ReactNative’sXHRimplementationis
basedontheMDNspecification.


UsingXHRfornetworkrequestsissomewhatmorecomplex,comparedwiththeFetch
API,butthebasicapproachshouldlooksomethinglikeExample6-9.


<i>Example6-9.BasicstructureforPOSTingaphotousingXHR</i>


<b>var</b>xhr=newXMLHttpRequest();



xhr.open('POST',' /><b>var</b>formdata=newFormData();


formdata.append('image',{...this.state.photo,name:'image.jpg'});


xhr.send(formdata);


</div>
<span class='text_page_counter'>(191)</span><div class='page_container' data-page=191>

<b>StoringPersistentDatawithAsyncStore</b>



Mostapplicationswillneedtokeeptrackofsomevarietyofdata,persistently.Howdo
youaccomplishthiswithReactNative?


iOSprovidesuswithAsyncStorage,akey-valuestorethatisglobaltoyourapplication.If
youhaveusedLocalStorageontheWeb,AsyncStorageoughttofeelquitesimilar.


AsyncStorage,asthenamesuggests,isasynchronous;itsAPIisquitesimple,too,anda


ReactNativemoduleforitisincludedbydefault.Let’stakealookathowtouseit.


ThestoragekeyusedbyAsyncStoragecanbeanystring;it’scustomarytousetheformat
@AppName:key,likeso:


varSTORAGE_KEY='@SmarterWeather:zip';


TheAsyncStoragemodulereturnsapromiseinresponsetobothgetItemandsetItem.
ForSmarterWeather,let’sloadthestoredzipcodeincomponentDidMount:


AsyncStorage.getItem(STORAGE_KEY)
.then((value)=>{
if(value!==null){


this._getForecastForZip(value);
}
})
.catch((error)=>console.log('AsyncStorageerror:'+error.message))
.done();


Then,in_getForecaseForZip,wecanstorethezipcodevalue:


</div>
<span class='text_page_counter'>(192)</span><div class='page_container' data-page=192>

<b>OtherStorageOptions</b>



<i>Ifyouareworkingwithmorecomplicated,structureddata,orsimplymoreofit,youwill</i>
likelywantoptionsbeyondasimplekey-valuestore.


</div>
<span class='text_page_counter'>(193)</span><div class='page_container' data-page=193>

<b>TheSmarterWeatherApplication</b>



</div>
<span class='text_page_counter'>(194)</span><div class='page_container' data-page=194></div>
<span class='text_page_counter'>(195)</span><div class='page_container' data-page=195>

<i>Figure6-9.ContentsoftheSmarterWeatherproject</i>


<i>Thetop-levelcomponentislocatedinweather_project.js.Sharedfontstylesarelocatedin</i>


<i>styles/typography.js.ThefoldersForecast/,PhotoBackdrop/,Button/,andLocationButton/</i>


</div>
<span class='text_page_counter'>(196)</span><div class='page_container' data-page=196>

<b>TheWeatherProjectComponent</b>



<i>Thetop-levelcomponentislocatedinweather_project.js(</i>Example6-10).Thisincludes
theuseofAsyncStoragetostorethemostrecentlocation.


<i>Example6-10.SmarterWeather/weather_project.js</i>


<b>var</b>React=require('react-native');
<b>var{</b>


StyleSheet,
Text,
View,
TextInput,
AsyncStorage,
Image


}=React;


<b>var</b>Forecast=require('./Forecast');


<b>var</b>LocationButton=require('./LocationButton');
<b>var</b>STORAGE_KEY='@SmarterWeather:zip';


<b>var</b>WEATHER_API_KEY='bbeb34ebf60ad50f7893e7440a1e2b0b';


<b>var</b>API_STEM=' />


<i>//Thisversionusesflowers.pngfromlocalassets</i>


<i>//varPhotoBackdrop=require('./PhotoBackdrop/local_image');</i>


<i>//Thisversionhasyoutopickaphoto</i>


<b>var</b>PhotoBackdrop=require('./PhotoBackdrop');


<i>//Thisversionpullsaspecifiedphotofromthecameraroll</i>


<i>//varPhotoBackdrop=require('./PhotoBackdrop/camera_roll_example');</i>


<b>var</b>WeatherProject=React.createClass({


getInitialState(){
return{
forecast:null
};
},
componentDidMount:function(){
AsyncStorage.getItem(STORAGE_KEY)
.then((value)=>{


if(value!==null){


this._getForecastForZip(value);
}


})


.catch((error)=>console.log('AsyncStorageerror:'+error.message))
.done();


},


_getForecastForZip:function(zip){
<i>//Storezipcode</i>


AsyncStorage.setItem(STORAGE_KEY,zip)


.then(()=>console.log('Savedselectiontodisk:'+zip))


.catch((error)=>console.log('AsyncStorageerror:'+error.message))
.done();



this._getForecast(


`${API_STEM}q=${zip}&units=imperial&APPID=${WEATHER_API_KEY}`);
},


_getForecastForCoords:function(lat,lon){
this._getForecast(


`${API_STEM}lat=${lat}&lon=${lon}&units=imperial&APPID=${WEATHER_API_KEY}`);
},


_getForecast:function(url,cb){
fetch(url)


.then((response)=>response.json())
.then((responseJSON)=>{


console.log(responseJSON);
this.setState({


forecast:{


</div>
<span class='text_page_counter'>(197)</span><div class='page_container' data-page=197>

description:responseJSON.weather[0].description,
temp:responseJSON.main.temp


}
});
})



.catch((error)=>{
console.warn(error);
});


},


_handleTextChange:function(event){
varzip=event.nativeEvent.text;
this._getForecastForZip(zip);
},


render:function(){
varcontent=null;


if(this.state.forecast!==null){
content=(


<Viewstyle={styles.row}>
<Forecast


main={this.state.forecast.main}


description={this.state.forecast.description}
temp={this.state.forecast.temp}/>


</View>);
}


return(



<PhotoBackdrop>


<Viewstyle={styles.overlay}>
<Viewstyle={styles.row}>


<Textstyle={textStyles.mainText}>
Currentweatherfor


</Text>


<Viewstyle={styles.zipContainer}>
<TextInput


style={[textStyles.mainText,styles.zipCode]}
returnKeyType='go'


onSubmitEditing={this._handleTextChange}/>
</View>


</View>


<Viewstyle={styles.row}>


<LocationButtononGetCoords={this._getForecastForCoords}/>
</View>


{content}
</View>


</PhotoBackdrop>


);


}
});


<b>var</b>textStyles=require('./styles/typography.js');
<b>var</b>styles=StyleSheet.create({


overlay:{
paddingTop:5,


backgroundColor:'#000000',
opacity:0.5,


},
row:{


width:400,
flex:1,


flexDirection:'row',
flexWrap:'nowrap',
alignItems:'center',
justifyContent:'center',
padding:30


},


zipContainer:{
flex:1,



borderBottomColor:'#DDDDDD',
borderBottomWidth:1,


marginLeft:5,
marginTop:3,
width:10


},


</div>
<span class='text_page_counter'>(198)</span><div class='page_container' data-page=198>

width:50,


height:textStyles.baseFontSize,
}


});


module.exports=WeatherProject;


<i>Itmakesuseofsharedstyleslocatedinstyles/typography.js(</i>Example6-11).


<i>Example6-11.SharedfontstylesarelocatedinSmarterWeather/styles/typography.js</i>


<b>var</b>React=require('react-native');


<b>var{</b>StyleSheet}=React;


<b>var</b>baseFontSize=18;


<b>var</b>styles=StyleSheet.create({


bigText:{


fontSize:baseFontSize+8,
color:'#FFFFFF'


},


mainText:{


fontSize:baseFontSize,
color:'#FFFFFF'


}
});


<i>//Foruseelsewhere…</i>


styles['baseFontSize']=baseFontSize;


</div>
<span class='text_page_counter'>(199)</span><div class='page_container' data-page=199>

<b>TheForecastComponent</b>



Thiscomponentdisplaystheforecastinformation,includingthetemperature.It’susedby
the<WeatherProject>componentabove.Thecodeforthe<Forecast>componentis
providedinExample6-12.


<i>Example6-12.Forecastcomponentrendersinformationabouttheforecast</i>


<b>var</b>React=require('react-native');


<b>var{</b>Text,View,StyleSheet}=React;



<b>var</b>styles=require('../styles/typography.js');
<b>var</b>Forecast=React.createClass({


render:function(){
return(


<Viewstyle={forecastStyles.forecast}>
<Textstyle={styles.bigText}>


{this.props.main}
</Text>


<Textstyle={styles.mainText}>


Currentconditions:{this.props.description}
</Text>


<Textstyle={styles.bigText}>
{this.props.temp}°F


</Text>
</View>
);


}
});


<b>var</b>forecastStyles=StyleSheet.create({
forecast:{



alignItems:'center'


}
});


</div>
<span class='text_page_counter'>(200)</span><div class='page_container' data-page=200>

<b>TheButtonComponent</b>




The<Button>componentisareusablecontainer-stylecomponent.Itprovidesaproperly-styled<Text>wrappedbya<TouchableHighlight>.Themaincomponentfileisprovided
inExample6-13,anditsassociatedstylesareprovidedinExample6-14.


<i>Example6-13.Buttoncomponentprovidesanappropriatelystyled<TouchableHighlight></i>
<i>containinga<Text></i>


<b>var</b>React=require('react-native');
<b>var{</b>


Text,
View,


TouchableHighlight


}=React;


<b>var</b>styles=require('./style.js');
<b>var</b>Button=React.createClass({
propTypes:{


onPress:React.PropTypes.func,


label:React.PropTypes.string


},


render:function(){
return(


<TouchableHighlightonPress={this.props.onPress}>
<Viewstyle={[styles.button,this.props.style]}>
<Text>


{this.props.label}
</Text>


</View>


</TouchableHighlight>
);


}
});


module.exports=Button;


<i>Example6-14.StylesfortheButtoncomponent</i>


<b>var</b>React=require('react-native');


<b>var{</b>StyleSheet}=React;



<b>var</b>baseFontSize=16;


<b>var</b>styles=StyleSheet.create({
button:{


backgroundColor:'#FFDDFF',
width:200,


padding:25,
borderRadius:5


},
});


</div>

<!--links-->
<a href=''></a>
<a href=' /><a href=' /><a href=' /><a href=' /><a href=''>LearningReactNative.com</a>
<a href=' /><a href=' /><a href=''>Havingobtainedacertificate,you’renearlydone.ThefinalstepistologontoApple</a>
<a href=' />

×