Table of Contents · npm run build : to build the React application files in the build folder,...

207

Transcript of Table of Contents · npm run build : to build the React application files in the build folder,...

Page 1: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm
Page 2: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TableofContentsIntroduction

Overview

IntroductiontoReact

HowtoinstallReact

ModernJavaScriptcoreconceptsyouneedtoknowtouseReact

HowmuchJSyouneedtouseReact

Variables

Arrowfunctions

WorkwithobjectsandarraysusingRestandSpread

Objectandarraydestructuring

Templateliterals

Classes

Callbacks

Promises

Async/Await

ESModules

ReactConcepts

SinglePageApps

Declarative

Immutability

Purity

Composition

TheVirtualDOM

UnidirectionalDataFlow

In-depth

JSX

Components

State

Props

Presentationalvscontainercomponents

2

Page 3: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

StatevsProps

PropTypes

Fragment

Events

Lifecycleevents

Handlingforms

ReferenceaDOMelement

Serversiderendering

ContextAPI

Higher-ordercomponents

RenderProps

Hooks

Codesplitting

Styling

CSSinReact

SASSwithReact

StyledComponents

Tooling

Babel

Webpack

Prettier

Testing

IntroductiontoJest

TestingReactComponents

AlookattheReactEcosystem

ReactRouter

Redux

Next.js

Gatsby

Wrappingup

3

Page 4: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

4

Page 5: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Introduction

TheReactHandbookfollowsthe80/20rule:learnin20%ofthetimethe80%ofatopic.

Ifindthisapproachgivesawell-roundedoverview.ThisbookdoesnottrytocovereverythingunderthesunrelatedtoReact.Ifyouthinksomespecifictopicshouldbeincluded,tellme.

InthisbookImakeuseofReacthooks,soyouneedtosettherequiredversionsofReactandReactDOMtouse 16.7.0-alpha.2(ifwhenyou'rereadingthisHooksarereleasedofficially,youdon'tneedtodothis).YoucandosoinCodeSandboxbyclicking"AddDependency"andsearching reactandchoosing 16.7.0-alpha.2fromtheselect,andrepeatthisfor react-dom.Whenusing create-react-app,run [email protected]@16.7.0-alpha.2afteryoucreatetheproject.

Ihopethecontentsofthisbookwillhelpyouachievewhatyouwant:learnthebasicsofReact.

ThisbookiswrittenbyFlavio.Ipublishwebdevelopmenttutorialseverydayonmywebsiteflaviocopes.com.

YoucanreachmeonTwitter@flaviocopes.

Introduction

5

Page 6: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Enjoy!

Introduction

6

Page 7: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

IntroductiontoReactAnintroductiontotheReactviewlibrary

WhatisReact?ReactisaJavaScriptlibrarythataimstosimplifydevelopmentofvisualinterfaces.

DevelopedatFacebookandreleasedtotheworldin2013,itdrivessomeofthemostwidelyusedapps,poweringFacebookandInstagramamongcountlessotherapplications.

Itsprimarygoalistomakeiteasytoreasonaboutaninterfaceanditsstateatanypointintime,bydividingtheUIintoacollectionofcomponents.

WhyisReactsopopular?Reacthastakenthefrontendwebdevelopmentworldbystorm.Why?

Lesscomplexthantheotheralternatives

AtthetimewhenReactwasannounced,Ember.jsandAngular1.xwerethepredominantchoicesasaframework.Boththeseimposedsomanyconventionsonthecodethatportinganexistingappwasnotconvenientatall.Reactmadeachoicetobeveryeasytointegrateintoanexistingproject,becausethat'showtheyhadtodoitatFacebookinordertointroduceittotheexistingcodebase.Also,those2frameworksbroughttoomuchtothetable,whileReactonlychosetoimplementtheViewlayerinsteadofthefullMVCstack.

Perfecttiming

Atthetime,Angular2.xwasannouncedbyGoogle,alongwiththebackwardsincompatibilityandmajorchangesitwasgoingtobring.MovingfromAngular1to2waslikemovingtoadifferentframework,sothis,alongwithexecutionspeedimprovementsthatReactpromised,madeitsomethingdeveloperswereeagertotry.

BackedbyFacebook

BeingbackedbyFacebookobviouslyisgoingtobenefitaprojectifitturnsouttobesuccessful.

IntroductiontoReact

7

Page 8: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

FacebookcurrentlyhasastronginterestinReact,seesthevalueofitbeingOpenSource,andthisisahugeplusforallthedevelopersusingitintheirownprojects.

IsReactsimpletolearn?EventhoughIsaidthatReactissimplerthanalternativeframeworks,divingintoReactisstillcomplicated,butmostlybecauseofthecorollarytechnologiesthatcanbeintegratedwithReact,likeReduxandGraphQL.

ReactinitselfhasaverysmallAPI,andyoubasicallyneedtounderstand4conceptstogetstarted:

ComponentsJSXStateProps

Allthese(andmore)areexplainedinthishandbook.

IntroductiontoReact

8

Page 9: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

HowtoinstallReactHowtoinstallReactonyourdevelopmentcomputer

HowdoyouinstallReact?

Reactisalibrary,sosayinginstallmightsoundabitweird.Maybesetupisabetterword,butyougettheconcept.

TherearevariouswaystosetupReactsothatitcanbeusedonyourapporsite.

LoadReactdirectlyinthewebpageThesimplestoneistoaddtheReactJavaScriptfileintothepagedirectly.ThisisbestwhenyourReactappwillinteractwiththeelementspresentonasinglepage,andnotactuallycontrolsthewholenavigationaspect.

Inthiscase,youadd2scripttagstotheendofthe bodytag:

<html>

...

<body>

...

<script

src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.developme

nt.js"

crossorigin

></script>

<script

src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.p

roduction.min.js"

crossorigin

></script>

</body>

</html>

The 16.7.0-alpha.2versioninthelinkspointstothelatestAlphaof16.7(atthetimeofwriting),whichhasHooksavailable.PleasechangeittothelatestversionofReactthatisavailable.

HereweloadedbothReactandReactDOM.Why2libraries?BecauseReactis100%independentfromthebrowserandcanbeusedoutsideit(forexampleonMobiledeviceswithReactNative).HencetheneedforReactDOM,toaddthewrappersforthebrowser.

HowtoinstallReact

9

Page 10: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

AfterthosetagsyoucanloadyourJavaScriptfilesthatuseReact,oreveninlineJavaScriptina scripttag:

<scriptsrc="app.js"></script>

<!--or-->

<script>

//myapp

</script>

TouseJSXyouneedanextrastep:loadBabel

<scriptsrc="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

andloadyourscriptswiththespecial text/babelMIMEtype:

<scriptsrc="app.js"type="text/babel"></script>

NowyoucanaddJSXinyourapp.jsfile:

constButton=()=>{

return<button>Clickme!</button>

}

ReactDOM.render(<Button/>,document.getElementById('root'))

CheckoutthissimpleGlitchexample:https://glitch.com/edit/#!/react-example-inline-jsx?path=script.js

Startinginthiswaywithscripttagsisgoodforbuildingprototypesandenablesaquickstartwithouthavingtosetupacomplexworkflow.

Usecreate-react-appcreate-react-appisaprojectaimedatgettingyouuptospeedwithReactinnotime,andanyReactappthatneedstooutgrowasinglepagewillfindthat create-react-appmeetsthatneed.

Youstartbyusing npx,whichisaneasywaytodownloadandexecuteNode.jscommandswithoutinstallingthem. npxcomeswith npm(sinceversion5.2)andifyoudon'thavenpminstalledalready,doitnowfromhttps://nodejs.org(npmisinstalledwithNode).

Ifyouareunsurewhichversionofnpmyouhave,run npm-vtocheckifyouneedtoupdate.

HowtoinstallReact

10

Page 11: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Tip:checkoutmyOSXterminaltutorialathttps://flaviocopes.com/macos-terminal/ifyou'reunfamiliarwithusingtheterminal,appliestoLinuxaswell-I'msorrybutIdon'thaveatutorialforWindowsatthemoment,butGoogleisyourfriend.

Whenyourun npxcreate-react-app<app-name>, npxisgoingtodownloadthemostrecentcreate-react-apprelease,runit,andthenremoveitfromyoursystem.Thisisgreatbecauseyouwillneverhaveanoutdatedversiononyoursystem,andeverytimeyourunit,you'regettingthelatestandgreatestcodeavailable.

Let'sstartthen:

npxcreate-react-apptodolist

Thisiswhenitfinishedrunning:

HowtoinstallReact

11

Page 12: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

create-react-appcreatedafilesstructureinthefolderyoutold( todolistinthiscase),andinitializedaGitrepository.

Italsoaddedafewcommandsinthe package.jsonfile,soyoucanimmediatelystarttheappbygoingintothefolderandrun npmstart.

HowtoinstallReact

12

Page 13: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Inadditionto npmstart, create-react-appaddedafewothercommands:

HowtoinstallReact

13

Page 14: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

npmrunbuild:tobuildtheReactapplicationfilesinthe buildfolder,readytobedeployedtoaservernpmtest:torunthetestingsuiteusingJestnpmeject:toejectfrom create-react-app

Ejectingistheactofdecidingthat create-react-apphasdoneenoughforyou,butyouwanttodomorethanwhatitallows.

Since create-react-appisasetofcommondenominatorconventionsandalimitedamountofoptions,it'sprobablethatatsomepointyourneedswilldemandsomethinguniquethatoutgrowsthecapabilitiesof create-react-app.

Whenyoueject,youlosetheabilityofautomaticupdatesbutyougainmoreflexibilityintheBabelandWebpackconfiguration.

Whenyouejecttheactionisirreversible.Youwillget2newfoldersinyourapplicationdirectory, configand scripts.Thosecontaintheconfigurations-andnowyoucanstarteditingthem.

IfyoualreadyhaveaReactappinstalledusinganolderversionofReact,firstchecktheversionbyadding console.log(React.version)inyourapp,thenyoucanupdatebyrunning [email protected],andyarnwillpromptyoutoupdate(choosethelatestversionavailable).Repeatfor [email protected](change"16.7"withwhateveristhenewestversionofReactatthemoment)

CodeSandboxAneasywaytohavethe create-react-appstructure,withoutinstallingit,istogotohttps://codesandbox.io/sandchoose"React".

HowtoinstallReact

14

Page 15: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CodeSandboxisagreatwaytostartaReactprojectwithouthavingtoinstallitlocally.

CodepenAnothergreatsolutionisCodepen.

YoucanusethisCodepenstarterprojectwhichalreadycomespre-configuredwithReact,withsupportforHooks:https://codepen.io/flaviocopes/pen/VqeaxB

Codepen"pens"aregreatforquickprojectswithoneJavaScriptfile,while"projects"aregreatforprojectswithmultiplefiles,liketheoneswe'llusethemostwhenbuildingReactapps.

OnethingtonoteisthatinCodepen,duetohowitworksinternally,youdon'tusetheregularESModules importsyntax,butrathertoimportforexample useState,youuse

HowtoinstallReact

15

Page 16: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

const{useState}=React

andnot

import{useState}from'react'

HowtoinstallReact

16

Page 17: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

HowmuchJSyouneedtouseReactFindoutifyouhavetolearnsomethingbeforedivingintolearningReact

IfyouarewillingtolearnReact,youfirstneedtohaveafewthingsunderyourbelt.Therearesomeprerequisitetechnologiesyouhavetobefamiliarwith,inparticularrelatedtosomeofthemorerecentJavaScriptfeaturesyou'lluseoverandoverinReact.

SometimespeoplethinkoneparticularfeatureisprovidedbyReact,butinsteadit'sjustmodernJavaScriptsyntax.

Thereisnopointinbeinganexpertinthosetopicsrightaway,butthemoreyoudiveintoReact,themoreyou'llneedtomasterthose.

Iwillmentionalistofthingstogetyouuptospeedquickly.

HowmuchJSyouneedtouseReact

17

Page 18: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

VariablesAvariableisaliteralassignedtoanidentifier,soyoucanreferenceanduseitlaterintheprogram.LearnhowtodeclareonewithJavaScript

Avariableisaliteralassignedtoanidentifier,soyoucanreferenceanduseitlaterintheprogram.

VariablesinJavaScriptdonothaveanytypeattached.Onceyouassignaspecificliteraltypetoavariable,youcanlaterreassignthevariabletohostanyothertype,withouttypeerrorsoranyissue.

ThisiswhyJavaScriptissometimesreferredtoas"untyped".

Avariablemustbedeclaredbeforeyoucanuseit.Thereare3waystodothis,using var,letor const,andthose3waysdifferinhowyoucaninteractwiththevariablelateron.

Using varUntilES2015, varwastheonlyconstructavailablefordefiningvariables.

vara=0

Ifyouforgettoadd varyouwillbeassigningavaluetoanundeclaredvariable,andtheresultsmightvary.

Inmodernenvironments,withstrictmodeenabled,youwillgetanerror.Inolderenvironments(orwithstrictmodedisabled)thiswillsimplyinitializethevariableandassignittotheglobalobject.

Ifyoudon'tinitializethevariablewhenyoudeclareit,itwillhavethe undefinedvalueuntilyouassignavaluetoit.

vara//typeofa==='undefined'

Youcanredeclarethevariablemanytimes,overridingit:

vara=1

vara=2

Youcanalsodeclaremultiplevariablesatonceinthesamestatement:

Variables

18

Page 19: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

vara=1,b=2

Thescopeistheportionofcodewherethevariableisvisible.

Avariableinitializedwith varoutsideofanyfunctionisassignedtotheglobalobject,hasaglobalscopeandisvisibleeverywhere.Avariableinitializedwith varinsideafunctionisassignedtothatfunction,it'slocalandisvisibleonlyinsideit,justlikeafunctionparameter.

Anyvariabledefinedinafunctionwiththesamenameasaglobalvariabletakesprecedenceovertheglobalvariable,shadowingit.

It'simportanttounderstandthatablock(identifiedbyapairofcurlybraces)doesnotdefineanewscope.Anewscopeisonlycreatedwhenafunctioniscreated,because vardoesnothaveblockscope,butfunctionscope.

Insideafunction,anyvariabledefinedinitisvisiblethroughoutallthefunctioncode,evenifthevariableisdeclaredattheendofthefunctionitcanstillbereferencedinthebeginning,becauseJavaScriptbeforeexecutingthecodeactuallymovesallvariablesontop(somethingthatiscalledhoisting).Toavoidconfusion,alwaysdeclarevariablesatthebeginningofafunction.

Using letletisanewfeatureintroducedinES2015andit'sessentiallyablockscopedversionofvar.Itsscopeislimitedtotheblock,statementorexpressionwhereit'sdefined,andallthecontainedinnerblocks.

ModernJavaScriptdevelopersmightchoosetoonlyuse letandcompletelydiscardtheuseof var.

If letseemsanobscureterm,justread letcolor='red'asletthecolorberedanditallmakesmuchmoresense

Defining letoutsideofanyfunction-contraryto var-doesnotcreateaglobalvariable.

Using constVariablesdeclaredwith varor letcanbechangedlateronintheprogram,andreassigned.Oncea constisinitialized,itsvaluecanneverbechangedagain,anditcan'tbereassignedtoadifferentvalue.

consta='test'

Variables

19

Page 20: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Wecan'tassignadifferentliteraltothe aconst.Wecanhowevermutate aifit'sanobjectthatprovidesmethodsthatmutateitscontents.

constdoesnotprovideimmutability,justmakessurethatthereferencecan'tbechanged.

consthasblockscope,sameas let.

ModernJavaScriptdevelopersmightchoosetoalwaysuse constforvariablesthatdon'tneedtobereassignedlaterintheprogram.

Why?Becauseweshouldalwaysusethesimplestconstructavailabletoavoidmakingerrorsdowntheroad.

Variables

20

Page 21: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ArrowfunctionsArrowFunctionsareoneofthemostimpactfulchangesinES6/ES2015,andtheyarewidelyusednowadays.Theyslightlydifferfromregularfunctions.Findouthow

ArrowfunctionswereintroducedinES6/ECMAScript2015,andsincetheirintroductiontheychangedforeverhowJavaScriptcodelooks(andworks).

Inmyopinionthischangewassowelcomingthatyounowrarelyseetheusageofthefunctionkeywordinmoderncodebases.

Visually,it’sasimpleandwelcomechange,whichallowsyoutowritefunctionswithashortersyntax,from:

constmyFunction=function(){

//...

}

to

constmyFunction=()=>{

//...

}

Ifthefunctionbodycontainsjustasinglestatement,youcanomitthebracketsandwriteallonasingleline:

constmyFunction=()=>doSomething()

Parametersarepassedintheparentheses:

constmyFunction=(param1,param2)=>doSomething(param1,param2)

Ifyouhaveone(andjustone)parameter,youcouldomittheparenthesescompletely:

constmyFunction=param=>doSomething(param)

Thankstothisshortsyntax,arrowfunctionsencouragetheuseofsmallfunctions.

Implicitreturn

Arrowfunctions

21

Page 22: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Arrowfunctionsallowyoutohaveanimplicitreturn:valuesarereturnedwithouthavingtousethe returnkeyword.

Itworkswhenthereisaone-linestatementinthefunctionbody:

constmyFunction=()=>'test'

myFunction()//'test'

Anotherexample,whenreturninganobject,remembertowrapthecurlybracketsinparenthesestoavoiditbeingconsideredthewrappingfunctionbodybrackets:

constmyFunction=()=>({value:'test'})

myFunction()//{value:'test'}

How thisworksinarrowfunctionsthisisaconceptthatcanbecomplicatedtograsp,asitvariesalotdependingonthecontextandalsovariesdependingonthemodeofJavaScript(strictmodeornot).

It'simportanttoclarifythisconceptbecausearrowfunctionsbehaveverydifferentlycomparedtoregularfunctions.

Whendefinedasamethodofanobject,inaregularfunction thisreferstotheobject,soyoucando:

constcar={

model:'Fiesta',

manufacturer:'Ford',

fullName:function(){

return`${this.manufacturer}${this.model}`

}

}

calling car.fullName()willreturn "FordFiesta".

The thisscopewitharrowfunctionsisinheritedfromtheexecutioncontext.Anarrowfunctiondoesnotbind thisatall,soitsvaluewillbelookedupinthecallstack,sointhiscode car.fullName()willnotwork,andwillreturnthestring "undefinedundefined":

constcar={

model:'Fiesta',

manufacturer:'Ford',

fullName:()=>{

Arrowfunctions

22

Page 23: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

return`${this.manufacturer}${this.model}`

}

}

Duetothis,arrowfunctionsarenotsuitedasobjectmethods.

Arrowfunctionscannotbeusedasconstructorseither,wheninstantiatinganobjectwillraiseaTypeError.

Thisiswhereregularfunctionsshouldbeusedinstead,whendynamiccontextisnotneeded.

Thisisalsoaproblemwhenhandlingevents.DOMEventlistenersset thistobethetargetelement,andifyourelyon thisinaneventhandler,aregularfunctionisnecessary:

constlink=document.querySelector('#link')

link.addEventListener('click',()=>{

//this===window

})

constlink=document.querySelector('#link')

link.addEventListener('click',function(){

//this===link

})

Arrowfunctions

23

Page 24: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

WorkwithobjectsandarraysusingRestandSpreadLearntwomoderntechniquestoworkwitharraysandobjectsinJavaScript

Youcanexpandanarray,anobjectorastringusingthespreadoperator ....

Let'sstartwithanarrayexample.Given

consta=[1,2,3]

youcancreateanewarrayusing

constb=[...a,4,5,6]

Youcanalsocreateacopyofanarrayusing

constc=[...a]

Thisworksforobjectsaswell.Cloneanobjectwith:

constnewObj={...oldObj}

Usingstrings,thespreadoperatorcreatesanarraywitheachcharinthestring:

consthey='hey'

constarrayized=[...hey]//['h','e','y']

Thisoperatorhassomeprettyusefulapplications.Themostimportantoneistheabilitytouseanarrayasfunctionargumentinaverysimpleway:

constf=(foo,bar)=>{}

consta=[1,2]

f(...a)

(inthepastyoucoulddothisusing f.apply(null,a)butthat'snotasniceandreadable)

Therestelementisusefulwhenworkingwitharraydestructuring:

constnumbers=[1,2,3,4,5]

[first,second,...others]=numbers

WorkwithobjectsandarraysusingRestandSpread

24

Page 25: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

andspreadelements:

constnumbers=[1,2,3,4,5]

constsum=(a,b,c,d,e)=>a+b+c+d+e

constsum=sum(...numbers)

ES2018introducesrestproperties,whicharethesamebutforobjects.

Restproperties:

const{first,second,...others}={

first:1,

second:2,

third:3,

fourth:4,

fifth:5

}

first//1

second//2

others//{third:3,fourth:4,fifth:5}

Spreadpropertiesallowtocreateanewobjectbycombiningthepropertiesoftheobjectpassedafterthespreadoperator:

constitems={first,second,...others}

items//{first:1,second:2,third:3,fourth:4,fifth:5}

WorkwithobjectsandarraysusingRestandSpread

25

Page 26: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ObjectandarraydestructuringLearnhowtousethedestructuringsyntaxtoworkwitharraysandobjectsinJavaScript

Givenanobject,usingthedestructuringsyntaxyoucanextractjustsomevaluesandputthemintonamedvariables:

constperson={

firstName:'Tom',

lastName:'Cruise',

actor:true,

age:54//madeup

}

const{firstName:name,age}=person//name:Tom,age:54

nameand agecontainthedesiredvalues.

Thesyntaxalsoworksonarrays:

consta=[1,2,3,4,5]

const[first,second]=a

Thisstatementcreates3newvariablesbygettingtheitemswithindex0,1,4fromthearraya:

const[first,second,,,fifth]=a

Objectandarraydestructuring

26

Page 27: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TemplateliteralsIntroducedinES2015,akaES6,TemplateLiteralsofferanewwaytodeclarestrings,butalsosomenewinterestingconstructswhicharealreadywidelypopular.

IntroductiontoTemplateLiteralsTemplateLiteralsareanewES2015/ES6featurethatallowsyoutoworkwithstringsinanovelwaycomparedtoES5andbelow.

Thesyntaxatafirstglanceisverysimple,justusebackticksinsteadofsingleordoublequotes:

consta_string=`something`

Theyareuniquebecausetheyprovidealotoffeaturesthatnormalstringsbuiltwithquotesdonot,inparticular:

theyofferagreatsyntaxtodefinemultilinestringstheyprovideaneasywaytointerpolatevariablesandexpressionsinstringstheyallowyoutocreateDSLswithtemplatetags(DSLmeansdomainspecificlanguage,andit'sforexampleusedinReactbyStyledComponents,todefineCSSforacomponent)

Let'sdiveintoeachoftheseindetail.

MultilinestringsPre-ES6,tocreateastringspanningovertwolinesyouhadtousethe \characterattheendofaline:

conststring=

'firstpart\

secondpart'

Thisallowstocreateastringon2lines,butit'srenderedonjustoneline:

firstpartsecondpart

Templateliterals

27

Page 28: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Torenderthestringonmultiplelinesaswell,youexplicitlyneedtoadd \nattheendofeachline,likethis:

conststring=

'firstline\n\

secondline'

or

conststring='firstline\n'+'secondline'

Templateliteralsmakemultilinestringsmuchsimpler.

Onceatemplateliteralisopenedwiththebacktick,youjustpressentertocreateanewline,withnospecialcharacters,andit'srenderedas-is:

conststring=`Hey

this

string

isawesome!`

Keepinmindthatspaceismeaningful,sodoingthis:

conststring=`First

Second`

isgoingtocreateastringlikethis:

First

Second

aneasywaytofixthisproblemisbyhavinganemptyfirstline,andappendingthetrim()methodrightaftertheclosingbacktick,whichwilleliminateanyspacebeforethefirstcharacter:

conststring=`

First

Second`.trim()

Interpolation

Templateliterals

28

Page 29: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Templateliteralsprovideaneasywaytointerpolatevariablesandexpressionsintostrings.

Youdosobyusingthe ${...}syntax:

constvar='test'

conststring=`something${var}`//somethingtest

insidethe ${}youcanaddanything,evenexpressions:

conststring=`something${1+2+3}`

conststring2=`something${foo()?'x':'y'}`

TemplatetagsTaggedtemplatesisonefeaturethatmightsoundlessusefulatfirstforyou,butit'sactuallyusedbylotsofpopularlibrariesaround,likeStyledComponentsorApollo,theGraphQLclient/serverlib,soit'sessentialtounderstandhowitworks.

InStyledComponentstemplatetagsareusedtodefineCSSstrings:

constButton=styled.button`

font-size:1.5em;

background-color:black;

color:white;

`

InApollotemplatetagsareusedtodefineaGraphQLqueryschema:

constquery=gql`

query{

...

}

`

The styled.buttonand gqltemplatetagshighlightedinthoseexamplesarejustfunctions:

functiongql(literals,...expressions){}

thisfunctionreturnsastring,whichcanbetheresultofanykindofcomputation.

literalsisanarraycontainingthetemplateliteralcontenttokenizedbytheexpressionsinterpolations.

expressionscontainsalltheinterpolations.

Templateliterals

29

Page 30: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Ifwetakeanexampleabove:

conststring=`something${1+2+3}`

literalsisanarraywithtwoitems.Thefirstis something,thestringuntilthefirstinterpolation,andthesecondisanemptystring,thespacebetweentheendofthefirstinterpolation(weonlyhaveone)andtheendofthestring.

expressionsinthiscaseisanarraywithasingleitem, 6.

Amorecomplexexampleis:

conststring=`something

another${'x'}

newline${1+2+3}

test`

inthiscase literalsisanarraywherethefirstitemis:

;`something

another`

thesecondis:

;`

newline`

andthethirdis:

;`

test`

expressionsinthiscaseisanarraywithtwoitems, xand 6.

Thefunctionthatispassedthosevaluescandoanythingwiththem,andthisisthepowerofthiskindfeature.

Themostsimpleexampleisreplicatingwhatthestringinterpolationdoes,bysimplyjoiningliteralsand expressions:

constinterpolated=interpolate`Ipaid${10}€`

andthisishow interpolateworks:

Templateliterals

30

Page 31: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

functioninterpolate(literals,...expressions){

letstring=``

for(const[i,val]ofexpressions){

string+=literals[i]+val

}

string+=literals[literals.length-1]

returnstring

}

Templateliterals

31

Page 32: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ClassesIn2015theECMAScript6(ES6)standardintroducedclasses.Learnallaboutthem

In2015theECMAScript6(ES6)standardintroducedclasses.

JavaScripthasaquiteuncommonwaytoimplementinheritance:prototypicalinheritance.Prototypalinheritance,whileinmyopiniongreat,isunlikemostotherpopularprogramminglanguage'simplementationofinheritance,whichisclass-based.

PeoplecomingfromJavaorPythonorotherlanguageshadahardtimeunderstandingtheintricaciesofprototypalinheritance,sotheECMAScriptcommitteedecidedtosprinklesyntacticsugarontopofprototypicalinheritancesothatitresembleshowclass-basedinheritanceworksinotherpopularimplementations.

Thisisimportant:JavaScriptunderthehoodisstillthesame,andyoucanaccessanobjectprototypeintheusualway.

AclassdefinitionThisishowaclasslooks.

classPerson{

constructor(name){

this.name=name

}

hello(){

return'Hello,Iam'+this.name+'.'

}

}

Aclasshasanidentifier,whichwecanusetocreatenewobjectsusing newClassIdentifier().

Whentheobjectisinitialized,the constructormethodiscalled,withanyparameterspassed.

Aclassalsohasasmanymethodsasitneeds.Inthiscase helloisamethodandcanbecalledonallobjectsderivedfromthisclass:

constflavio=newPerson('Flavio')

flavio.hello()

Classes

32

Page 33: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ClassinheritanceAclasscanextendanotherclass,andobjectsinitializedusingthatclassinheritallthemethodsofbothclasses.

Iftheinheritedclasshasamethodwiththesamenameasoneoftheclasseshigherinthehierarchy,theclosestmethodtakesprecedence:

classProgrammerextendsPerson{

hello(){

returnsuper.hello()+'Iamaprogrammer.'

}

}

constflavio=newProgrammer('Flavio')

flavio.hello()

(theaboveprogramprints"Hello,IamFlavio.Iamaprogrammer.")

Classesdonothaveexplicitclassvariabledeclarations,butyoumustinitializeanyvariableintheconstructor.

Insideaclass,youcanreferencetheparentclasscalling super().

StaticmethodsNormallymethodsaredefinedontheinstance,notontheclass.

Staticmethodsareexecutedontheclassinstead:

classPerson{

staticgenericHello(){

return'Hello'

}

}

Person.genericHello()//Hello

PrivatemethodsJavaScriptdoesnothaveabuilt-inwaytodefineprivateorprotectedmethods.

Thereareworkarounds,butIwon'tdescribethemhere.

Classes

33

Page 34: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

GettersandsettersYoucanaddmethodsprefixedwith getor settocreateagetterandsetter,whicharetwodifferentpiecesofcodethatareexecutedbasedonwhatyouaredoing:accessingthevariable,ormodifyingitsvalue.

classPerson{

constructor(name){

this.name=name

}

setname(value){

this.name=value

}

getname(){

returnthis.name

}

}

Ifyouonlyhaveagetter,thepropertycannotbeset,andanyattemptatdoingsowillbeignored:

classPerson{

constructor(name){

this.name=name

}

getname(){

returnthis.name

}

}

Ifyouonlyhaveasetter,youcanchangethevaluebutnotaccessitfromtheoutside:

classPerson{

constructor(name){

this.name=name

}

setname(value){

this.name=value

}

}

Classes

34

Page 35: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Classes

35

Page 36: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PromisesPromisesareonewaytodealwithasynchronouscodeinJavaScript,withoutwritingtoomanycallbacksinyourcode.

Apromiseiscommonlydefinedasaproxyforavaluethatwilleventuallybecomeavailable.

Promisesareonewaytodealwithasynchronouscode,withoutwritingtoomanycallbacksinyourcode.

Althoughthey'vebeenaroundforyears,theywerestandardizedandintroducedinES2015,andnowtheyhavebeensupersededinES2017byasyncfunctions.

AsyncfunctionsusethepromisesAPIastheirbuildingblock,sounderstandingthemisfundamentalevenifinnewercodeyou'lllikelyuseasyncfunctionsinsteadofpromises.

Howpromiseswork,inbrief

Onceapromisehasbeencalled,itwillstartinpendingstate.Thismeansthatthecallerfunctioncontinuestheexecution,whileitwaitsforthepromisetodoitsownprocessing,andgivethecallerfunctionsomefeedback.

Atthispoint,thecallerfunctionwaitsforittoeitherreturnthepromiseinaresolvedstate,orinarejectedstate,butasyouknowJavaScriptisasynchronous,sothefunctioncontinuesitsexecutionwhilethepromisedoesitwork.

WhichJSAPIusepromises?

Inadditiontoyourowncodeandlibrarycode,promisesareusedbystandardmodernWebAPIssuchas:

theBatteryAPItheFetchAPIServiceWorkers

It'sunlikelythatinmodernJavaScriptyou'llfindyourselfnotusingpromises,solet'sstartdivingrightintothem.

Creatingapromise

Promises

36

Page 37: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ThePromiseAPIexposesaPromiseconstructor,whichyouinitializeusing newPromise():

letdone=true

constisItDoneYet=newPromise((resolve,reject)=>{

if(done){

constworkDone='HereisthethingIbuilt'

resolve(workDone)

}else{

constwhy='Stillworkingonsomethingelse'

reject(why)

}

})

Asyoucanseethepromisechecksthe doneglobalconstant,andifthat'strue,wereturnaresolvedpromise,otherwisearejectedpromise.

Using resolveand rejectwecancommunicatebackavalue,intheabovecasewejustreturnastring,butitcouldbeanobjectaswell.

ConsumingapromiseInthelastsection,weintroducedhowapromiseiscreated.

Nowlet'sseehowthepromisecanbeconsumedorused.

constisItDoneYet=newPromise()

//...

constcheckIfItsDone=()=>{

isItDoneYet

.then(ok=>{

console.log(ok)

})

.catch(err=>{

console.error(err)

})

}

Running checkIfItsDone()willexecutethe isItDoneYet()promiseandwillwaitforittoresolve,usingthe thencallback,andifthereisanerror,itwillhandleitinthe catchcallback.

Promises

37

Page 38: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ChainingpromisesApromisecanbereturnedtoanotherpromise,creatingachainofpromises.

AgreatexampleofchainingpromisesisgivenbytheFetchAPI,alayerontopoftheXMLHttpRequestAPI,whichwecanusetogetaresourceandqueueachainofpromisestoexecutewhentheresourceisfetched.

TheFetchAPIisapromise-basedmechanism,andcalling fetch()isequivalenttodefiningourownpromiseusing newPromise().

Exampleofchainingpromises

conststatus=response=>{

if(response.status>=200&&response.status<300){

returnPromise.resolve(response)

}

returnPromise.reject(newError(response.statusText))

}

constjson=response=>response.json()

fetch('/todos.json')

.then(status)

.then(json)

.then(data=>{

console.log('RequestsucceededwithJSONresponse',data)

})

.catch(error=>{

console.log('Requestfailed',error)

})

Inthisexample,wecall fetch()togetalistofTODOitemsfromthe todos.jsonfilefoundinthedomainroot,andwecreateachainofpromises.

Running fetch()returnsaresponse,whichhasmanyproperties,andwithinthosewereference:

status,anumericvaluerepresentingtheHTTPstatuscodestatusText,astatusmessage,whichis OKiftherequestsucceeded

responsealsohasa json()method,whichreturnsapromisethatwillresolvewiththecontentofthebodyprocessedandtransformedintoJSON.

Sogiventhosepremises,thisiswhathappens:thefirstpromiseinthechainisafunctionthatwedefined,called status(),thatcheckstheresponsestatusandifit'snotasuccessresponse(between200and299),itrejectsthepromise.

Promises

38

Page 39: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thisoperationwillcausethepromisechaintoskipallthechainedpromiseslistedandwillskipdirectlytothe catch()statementatthebottom,loggingthe Requestfailedtextalongwiththeerrormessage.

Ifthatsucceedsinstead,itcallsthejson()functionwedefined.Sincethepreviouspromise,whensuccessful,returnedthe responseobject,wegetitasaninputtothesecondpromise.

Inthiscase,wereturnthedataJSONprocessed,sothethirdpromisereceivestheJSONdirectly:

.then((data)=>{

console.log('RequestsucceededwithJSONresponse',data)

})

andwesimplylogittotheconsole.

HandlingerrorsIntheaboveexample,intheprevioussection,wehada catchthatwasappendedtothechainofpromises.

Whenanythinginthechainofpromisesfailsandraisesanerrororrejectsthepromise,thecontrolgoestothenearest catch()statementdownthechain.

newPromise((resolve,reject)=>{

thrownewError('Error')

}).catch(err=>{

console.error(err)

})

//or

newPromise((resolve,reject)=>{

reject('Error')

}).catch(err=>{

console.error(err)

})

Cascadingerrors

Ifinsidethe catch()youraiseanerror,youcanappendasecond catch()tohandleit,andsoon.

newPromise((resolve,reject)=>{

Promises

39

Page 40: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

thrownewError('Error')

})

.catch(err=>{

thrownewError('Error')

})

.catch(err=>{

console.error(err)

})

Orchestratingpromises

Promise.all()

Ifyouneedtosynchronizedifferentpromises, Promise.all()helpsyoudefinealistofpromises,andexecutesomethingwhentheyareallresolved.

Example:

constf1=fetch('/something.json')

constf2=fetch('/something2.json')

Promise.all([f1,f2])

.then(res=>{

console.log('Arrayofresults',res)

})

.catch(err=>{

console.error(err)

})

TheES2015destructuringassignmentsyntaxallowsyoutoalsodo

Promise.all([f1,f2]).then(([res1,res2])=>{

console.log('Results',res1,res2)

})

Youarenotlimitedtousing fetchofcourse,anypromiseisgoodtogo.

Promise.race()

Promise.race()runsassoonasoneofthepromisesyoupasstoitresolves,anditrunstheattachedcallbackjustoncewiththeresultofthefirstpromiseresolved.

Example:

constpromiseOne=newPromise((resolve,reject)=>{

Promises

40

Page 41: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

setTimeout(resolve,500,'one')

})

constpromiseTwo=newPromise((resolve,reject)=>{

setTimeout(resolve,100,'two')

})

Promise.race([promiseOne,promiseTwo]).then(result=>{

console.log(result)//'two'

})

Commonerrors

UncaughtTypeError:undefinedisnotapromise

Ifyougetthe UncaughtTypeError:undefinedisnotapromiseerrorintheconsole,makesureyouuse newPromise()insteadofjust Promise()

Promises

41

Page 42: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Async/AwaitDiscoverthemodernapproachtoasynchronousfunctionsinJavaScript.JavaScriptevolvedinaveryshorttimefromcallbackstoPromises,andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax

IntroductionJavaScriptevolvedinaveryshorttimefromcallbackstopromises(ES2015),andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax.

Asyncfunctionsareacombinationofpromisesandgenerators,andbasically,theyareahigherlevelabstractionoverpromises.Letmerepeat:async/awaitisbuiltonpromises.

Whywereasync/awaitintroduced?Theyreducetheboilerplatearoundpromises,andthe"don'tbreakthechain"limitationofchainingpromises.

WhenPromiseswereintroducedinES2015,theyweremeanttosolveaproblemwithasynchronouscode,andtheydid,butoverthe2yearsthatseparatedES2015andES2017,itwasclearthatpromisescouldnotbethefinalsolution.

Promiseswereintroducedtosolvethefamouscallbackhellproblem,buttheyintroducedcomplexityontheirown,andsyntaxcomplexity.

Theyweregoodprimitivesaroundwhichabettersyntaxcouldbeexposedtodevelopers,sowhenthetimewasrightwegotasyncfunctions.

Theymakethecodelooklikeit'ssynchronous,butit'sasynchronousandnon-blockingbehindthescenes.

HowitworksAnasyncfunctionreturnsapromise,likeinthisexample:

constdoSomethingAsync=()=>{

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

Async/Await

42

Page 43: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

}

Whenyouwanttocallthisfunctionyouprepend await,andthecallingcodewillstopuntilthepromiseisresolvedorrejected.Onecaveat:theclientfunctionmustbedefinedasasync.Here'sanexample:

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

AquickexampleThisisasimpleexampleofasync/awaitusedtorunafunctionasynchronously:

constdoSomethingAsync=()=>{

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

}

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

console.log('Before')

doSomething()

console.log('After')

Theabovecodewillprintthefollowingtothebrowserconsole:

Before

After

Ididsomething//after3s

PromiseallthethingsPrependingthe asynckeywordtoanyfunctionmeansthatthefunctionwillreturnapromise.

Evenifit'snotdoingsoexplicitly,itwillinternallymakeitreturnapromise.

Thisiswhythiscodeisvalid:

constaFunction=async()=>{

return'test'

}

Async/Await

43

Page 44: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

aFunction().then(alert)//Thiswillalert'test'

andit'sthesameas:

constaFunction=async()=>{

returnPromise.resolve('test')

}

aFunction().then(alert)//Thiswillalert'test'

ThecodeismuchsimplertoreadAsyoucanseeintheexampleabove,ourcodelooksverysimple.Compareittocodeusingplainpromises,withchainingandcallbackfunctions.

Andthisisaverysimpleexample,themajorbenefitswillarisewhenthecodeismuchmorecomplex.

Forexamplehere'showyouwouldgetaJSONresource,andparseit,usingpromises:

constgetFirstUserData=()=>{

returnfetch('/users.json')//getuserslist

.then(response=>response.json())//parseJSON

.then(users=>users[0])//pickfirstuser

.then(user=>fetch(`/users/${user.name}`))//getuserdata

.then(userResponse=>response.json())//parseJSON

}

getFirstUserData()

Andhereisthesamefunctionalityprovidedusingawait/async:

constgetFirstUserData=async()=>{

constresponse=awaitfetch('/users.json')//getuserslist

constusers=awaitresponse.json()//parseJSON

constuser=users[0]//pickfirstuser

constuserResponse=awaitfetch(`/users/${user.name}`)//getuserdata

constuserData=awaituser.json()//parseJSON

returnuserData

}

getFirstUserData()

Multipleasyncfunctionsinseries

Async/Await

44

Page 45: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Asyncfunctionscanbechainedveryeasily,andthesyntaxismuchmorereadablethanwithplainpromises:

constpromiseToDoSomething=()=>{

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),10000)

})

}

constwatchOverSomeoneDoingSomething=async()=>{

constsomething=awaitpromiseToDoSomething()

returnsomething+'andIwatched'

}

constwatchOverSomeoneWatchingSomeoneDoingSomething=async()=>{

constsomething=awaitwatchOverSomeoneDoingSomething()

returnsomething+'andIwatchedaswell'

}

watchOverSomeoneWatchingSomeoneDoingSomething().then(res=>{

console.log(res)

})

Willprint:

IdidsomethingandIwatchedandIwatchedaswell

EasierdebuggingDebuggingpromisesishardbecausethedebuggerwillnotstepoverasynchronouscode.

Async/awaitmakesthisveryeasybecausetothecompilerit'sjustlikesynchronouscode.

Async/Await

45

Page 46: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ESModulesESModulesistheECMAScriptstandardforworkingwithmodules.WhileNode.jshasbeenusingtheCommonJSstandardforyears,thebrowserneverhadamodulesystem,aseverymajordecisionsuchasamodulesystemmustbefirststandardizedbyECMAScriptandthenimplemented

ESModulesistheECMAScriptstandardforworkingwithmodules.

WhileNode.jshasbeenusingtheCommonJSstandardforyears,thebrowserneverhadamodulesystem,aseverymajordecisionsuchasamodulesystemmustbefirststandardizedbyECMAScriptandthenimplementedbythebrowser.

ThisstandardizationprocesscompletedwithES6andbrowsersstartedimplementingthisstandardtryingtokeepeverythingwellaligned,workingallinthesameway,andnowESModulesaresupportedinChrome,Safari,EdgeandFirefox(sinceversion60).

Modulesareverycool,becausetheyletyouencapsulateallsortsoffunctionality,andexposethisfunctionalitytootherJavaScriptfiles,aslibraries.

ESModules

46

Page 47: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TheESModulesSyntaxThesyntaxtoimportamoduleis:

importpackagefrom'module-name'

whileCommonJSuses

constpackage=require('module-name')

AmoduleisaJavaScriptfilethatexportsoneormorevalues(objects,functionsorvariables),usingthe exportkeyword.Forexample,thismoduleexportsafunctionthatreturnsastringuppercase:

uppercase.js

exportdefaultstr=>str.toUpperCase()

Inthisexample,themoduledefinesasingle,defaultexport,soitcanbeananonymousfunction.Otherwiseitwouldneedanametodistinguishitfromotherexports.

ESModules

47

Page 48: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Now,anyotherJavaScriptmodulecanimportthefunctionalityofferedbyuppercase.jsbyimportingit.

AnHTMLpagecanaddamodulebyusinga <script>tagwiththespecial type="module"attribute:

<scripttype="module"src="index.js"></script>

Note:thismoduleimportbehaveslikea deferscriptload.SeeefficientlyloadJavaScriptwithdeferandasync

It'simportanttonotethatanyscriptloadedwith type="module"isloadedinstrictmode.

Inthisexample,the uppercase.jsmoduledefinesadefaultexport,sowhenweimportit,wecanassignitanameweprefer:

importtoUpperCasefrom'./uppercase.js'

andwecanuseit:

toUpperCase('test')//'TEST'

Youcanalsouseanabsolutepathforthemoduleimport,toreferencemodulesdefinedonanotherdomain:

importtoUpperCasefrom'https://flavio-es-modules-example.glitch.me/uppercase.js'

Thisisalsovalidimportsyntax:

import{foo}from'/uppercase.js'

import{foo}from'../uppercase.js'

Thisisnot:

import{foo}from'uppercase.js'

import{foo}from'utils/uppercase.js'

It'seitherabsolute,orhasa ./or /beforethename.

Otherimport/exportoptions

ESModules

48

Page 49: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Wesawthisexampleabove:

exportdefaultstr=>str.toUpperCase()

Thiscreatesonedefaultexport.Inafilehoweveryoucanexportmorethanonething,byusingthissyntax:

consta=1

constb=2

constc=3

export{a,b,c}

Anothermodulecanimportallthoseexportsusing

import*from'module'

Youcanimportjustafewofthoseexports,usingthedestructuringassignment:

import{a}from'module'

import{a,b}from'module'

Youcanrenameanyimport,forconvenience,using as:

import{a,bastwo}from'module'

Youcanimportthedefaultexport,andanynon-defaultexportbyname,likeinthiscommonReactimport:

importReact,{Component}from'react'

YoucanseeanESModulesexamplehere:https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html

CORSModulesarefetchedusingCORS.Thismeansthatifyoureferencescriptsfromotherdomains,theymusthaveavalidCORSheaderthatallowscross-siteloading(like Access-Control-Allow-Origin:*)

ESModules

49

Page 50: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Whataboutbrowsersthatdonotsupportmodules?Useacombinationof type="module"and nomodule:

<scripttype="module"src="module.js"></script>

<scriptnomodulesrc="fallback.js"></script>

ConclusionESModulesareoneofthebiggestfeaturesintroducedinmodernbrowsers.TheyarepartofES6buttheroadtoimplementthemhasbeenlong.

Wecannowusethem!Butwemustalsorememberthathavingmorethanafewmodulesisgoingtohaveaperformancehitonourpages,asit'sonemorestepthatthebrowsermustperformatruntime.

WebpackisprobablygoingtostillbeahugeplayerevenifESModuleslandinthebrowser,buthavingsuchafeaturedirectlybuiltinthelanguageishugeforaunificationofhowmodulesworkclient-sideandonNode.jsaswell.

ESModules

50

Page 51: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

SinglePageAppsReactApplicationsarealsocalledSinglePageApplications.Whatdoesthismean?

Inthepast,whenbrowsersweremuchlesscapablethantoday,andJavaScriptperformancewaspoor,everypagewascomingfromaserver.Everytimeyouclickedsomething,anewrequestwasmadetotheserverandthebrowsersubsequentlyloadedthenewpage.

Onlyveryinnovativeproductsworkeddifferently,andexperimentedwithnewapproaches.

Today,popularizedbymodernfrontendJavaScriptframeworkslikeReact,anappisusuallybuiltasasinglepageapplication:youonlyloadtheapplicationcode(HTML,CSS,JavaScript)once,andwhenyouinteractwiththeapplication,whatgenerallyhappensisthatJavaScriptinterceptsthebrowsereventsandinsteadofmakinganewrequesttotheserverthatthenreturnsanewdocument,theclientrequestssomeJSONorperformsanactionontheserverbutthepagethattheuserseesisnevercompletelywipedaway,andbehavesmorelikeadesktopapplication.

SinglepageapplicationsarebuiltinJavaScript(oratleastcompiledtoJavaScript)andworkinthebrowser.

Thetechnologyisalwaysthesame,butthephilosophyandsomekeycomponentsofhowtheapplicationworksaredifferent.

ExamplesofSinglePageApplicationsSomenotableexamples:

GmailGoogleMapsFacebookTwitterGoogleDrive

ProsandconsofSPAsAnSPAfeelsmuchfastertotheuser,becauseinsteadofwaitingfortheclient-servercommunicationtohappen,andwaitforthebrowsertore-renderthepage,youcannowhaveinstantfeedback.Thisistheresponsibilityoftheapplicationmaker,butyoucanhave

SinglePageApps

51

Page 52: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

transitionsandspinnersandanykindofUXimprovementthatiscertainlybetterthanthetraditionalworkflow.

Inadditiontomakingtheexperiencefastertotheuser,theserverwillconsumelessresourcesbecauseyoucanfocusonprovidinganefficientAPIinsteadofbuildingthelayoutsserver-side.

ThismakesitidealifyoualsobuildamobileappontopoftheAPI,asyoucancompletelyreuseyourexistingserver-sidecode.

SinglePageApplicationsareeasytotransformintoProgressiveWebApps,whichinturnenablesyoutoprovidelocalcachingandtosupportofflineexperiencesforyourservices(orsimplyabettererrormessageifyourusersneedtobeonline).

SPAsarebestusedwhenthereisnoneedforSEO(searchengineoptimization).Forexampleforappsthatworkbehindalogin.

Searchengines,whileimprovingeveryday,stillhavetroubleindexingsitesbuiltwithanSPAapproachratherthanthetraditionalserver-renderedpages.Thisisthecaseforblogs.Ifyouaregoingtorelyonsearchengines,don'tevenbotherwithcreatingasinglepageapplicationwithouthavingaserverrenderedpartaswell.

WhencodinganSPA,youaregoingtowriteagreatdealofJavaScript.Sincetheappcanbelong-running,youaregoingtoneedtopayalotmoreattentiontopossiblememoryleaks-ifinthepastyourpagehadalifespanthatwascountedinminutes,nowanSPAmightstayopenforhoursatatimeandifthereisanymemoryissuethat'sgoingtoincreasethebrowsermemoryusagebyalotmoreandit'sgoingtocauseanunpleasantlyslowexperienceifyoudon'ttakecareofit.

SPAsaregreatwhenworkinginteams.BackenddeveloperscanjustfocusontheAPI,andfrontenddeveloperscanfocusoncreatingthebestuserexperience,makinguseoftheAPIbuiltinthebackend.

Asacon,SinglePageAppsrelyheavilyonJavaScript.Thismightmakeusinganapplicationrunningonlowpowerdevicesapoorexperienceintermsofspeed.Also,someofyourvisitorsmightjusthaveJavaScriptdisabled,andyoualsoneedtoconsideraccessibilityforanythingyoubuild.

OverridingthenavigationSinceyougetridofthedefaultbrowsernavigation,URLsmustbemanagedmanually.

Thispartofanapplicationiscalledtherouter.Someframeworksalreadytakecareofthemforyou(likeEmber),othersrequirelibrariesthatwilldothisjob(likeReactRouter).

SinglePageApps

52

Page 53: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

What'stheproblem?Inthebeginning,thiswasanafterthoughtfordevelopersbuildingSinglePageApplications.Thiscausedthecommon"brokenbackbutton"issue:whennavigatinginsidetheapplicationtheURLdidn'tchange(sincethebrowserdefaultnavigationwashijacked)andhittingthebackbutton,acommonoperationthatusersdotogotothepreviousscreen,mightmovetoawebsiteyouvisitedalongtimeago.

ThisproblemcannowbesolvedusingtheHistoryAPIofferedbybrowsers,butmostofthetimeyou'llusealibrarythatinternallyusesthatAPI,likeReactRouter.

SinglePageApps

53

Page 54: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

DeclarativeWhatdoesitmeanwhenyoureadthatReactisdeclarative

You'llrunacrossarticlesdescribingReactasadeclarativeapproachtobuildingUIs.

Reactmadeits"declarativeapproach"quitepopularandupfrontsoitpermeatedthefrontendworldalongwithReact.

It'sreallynotanewconcept,butReacttookbuildingUIsalotmoredeclarativelythanwithHTMLtemplates:

youcanbuildWebinterfaceswithouteventouchingtheDOMdirectlyyoucanhaveaneventsystemwithouthavingtointeractwiththeactualDOMEvents.

Theoppositeofdeclarativeisiterative.AcommonexampleofaniterativeapproachislookingupelementsintheDOMusingjQueryorDOMevents.Youtellthebrowserexactlywhattodo,insteadoftellingitwhatyouneed.

TheReactdeclarativeapproachabstractsthatforus.WejusttellReactwewantacomponenttoberenderedinaspecificway,andweneverhavetointeractwiththeDOMtoreferenceitlater.

Declarative

54

Page 55: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ImmutabilityWhatisimmutability?AndhowdoesitfitintheReactworld?

OneconceptyouwilllikelymeetwhenprogramminginReactisimmutability(anditsopposite,mutability).

It'sacontroversialtopic,butwhateveryoumightthinkabouttheconceptofimmutability,Reactandmostofitsecosystemkindofforcesthis,soyouneedtoatleasthaveagraspofwhyit'ssoimportantandtheimplicationsofit.

Inprogramming,avariableisimmutablewhenitsvaluecannotchangeafterit'screated.

Youarealreadyusingimmutablevariableswithoutknowingitwhenyoumanipulateastring.Stringsareimmutablebydefault,whenyouchangetheminrealityyoucreateanewstringandassignittothesamevariablename.

Animmutablevariablecanneverbechanged.Toupdateitsvalue,youcreateanewvariable.

Thesameappliestoobjectsandarrays.

Insteadofchanginganarray,toaddanewitemyoucreateanewarraybyconcatenatingtheoldarray,plusthenewitem.

Anobjectisneverupdated,butcopiedbeforechangingit.

ThisappliestoReactinmanyplaces.

Forexample,youshouldnevermutatethe statepropertyofacomponentdirectly,butonlythroughthe setState()method.

InRedux,younevermutatethestatedirectly,butonlythroughreducers,whicharefunctions.

Thequestionis,why?

Therearevariousreasons,themostimportantofwhichare:

Mutationscanbecentralized,likeinthecaseofRedux,whichimprovesyourdebuggingcapabilitiesandreducessourcesoferrors.Codelookscleanerandsimplertounderstand.Youneverexpectafunctiontochangesomevaluewithoutyouknowing,whichgivesyoupredictability.Whenafunctiondoesnotmutateobjectsbutjustreturnsanewobject,it'scalledapurefunction.ThelibrarycanoptimizethecodebecauseforexampleJavaScriptisfasterwhenswappinganoldobjectreferenceforanentirelynewobject,ratherthanmutatinganexistingobject.Thisgivesyouperformance.

Immutability

55

Page 56: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Immutability

56

Page 57: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PurityWhatispurity,apurefunctionandapurecomponent

InJavaScript,whenafunctiondoesnotmutateobjectsbutjustreturnsanewobject,it'scalledapurefunction.

Afunction,oramethod,inordertobecalledpureshouldnotcausesideeffectsandshouldreturnthesameoutputwhencalledmultipletimeswiththesameinput.

Apurefunctiontakesaninputandreturnsanoutputwithoutchangingtheinputnoranythingelse.

Itsoutputisonlydeterminedbythearguments.Youcouldcallthisfunction1Mtimes,andgiventhesamesetofarguments,theoutputwillalwaysbethesame.

Reactappliesthisconcepttocomponents.AReactcomponentisapurecomponentwhenitsoutputisonlydependantonitsprops.

Allfunctionalcomponentsarepurecomponents:

constButton=props=>{

return<button>{props.message}</button>

}

Classcomponentscanbepureiftheiroutputonlydependsontheprops:

classButtonextendsReact.Component{

render(){

return<button>{this.props.message}</button>

}

}

Purity

57

Page 58: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CompositionWhatiscompositionandwhyisitakeyconceptinyourReactapps

Inprogramming,compositionallowsyoutobuildmorecomplexfunctionalitybycombiningsmallandfocusedfunctions.

Forexample,thinkaboutusing map()tocreateanewarrayfromaninitialset,andthenfilteringtheresultusing filter():

constlist=['Apple','Orange','Egg']

list.map(item=>item[0]).filter(item=>item==='A')//'A'

InReact,compositionallowsyoutohavesomeprettycooladvantages.

Youcreatesmallandleancomponentsandusethemtocomposemorefunctionalityontopofthem.How?

CreatespecializedversionofacomponentUseanoutercomponenttoexpandandspecializeamoregenericcomponent:

constButton=props=>{

return<button>{props.text}</button>

}

constSubmitButton=()=>{

return<Buttontext="Submit"/>

}

constLoginButton=()=>{

return<Buttontext="Login"/>

}

PassmethodsaspropsAcomponentcanfocusontrackingaclickevent,forexample,andwhatactuallyhappenswhentheclickeventhappensisuptothecontainercomponent:

constButton=props=>{

return<buttononClick={props.onClickHandler}>{props.text}</button>

}

Composition

58

Page 59: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

constLoginButton=props=>{

return<Buttontext="Login"onClickHandler={props.onClickHandler}/>

}

constContainer=()=>{

constonClickHandler=()=>{

alert('clicked')

}

return<LoginButtononClickHandler={onClickHandler}/>

}

UsingchildrenThe props.childrenpropertyallowsyoutoinjectcomponentsinsideothercomponents.

Thecomponentneedstooutput props.childreninitsJSX:

constSidebar=props=>{

return<aside>{props.children}</aside>

}

andyouembedmorecomponentsintoitinatransparentway:

<Sidebar>

<Linktitle="Firstlink"/>

<Linktitle="Secondlink"/>

</Sidebar>

HigherordercomponentsWhenacomponentreceivesacomponentasapropandreturnsacomponent,it'scalledhigherordercomponent.

We'llseetheminalittlewhile.

Composition

59

Page 60: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TheVirtualDOMTheVirtualDOMisatechniquethatReactusestooptimizeinteractingwiththebrowser

Manyexistingframeworks,beforeReactcameonthescene,weredirectlymanipulatingtheDOMoneverychange.

First,whatistheDOM?

TheDOM(DocumentObjectModel)isaTreerepresentationofthepage,startingfromthe<html>tag,goingdownintoeverychild,whicharecallednodes.

It'skeptinthebrowsermemory,anddirectlylinkedtowhatyouseeinapage.TheDOMhasanAPIthatyoucanusetotraverseit,accesseverysinglenode,filterthem,modifythem.

TheAPIisthefamiliarsyntaxyouhavelikelyseenmanytimes,ifyouwerenotusingtheabstractAPIprovidedbyjQueryandfriends:

document.getElementById(id)

document.getElementsByTagName(name)

document.createElement(name)

parentNode.appendChild(node)

element.innerHTML

element.style.left

element.setAttribute()

element.getAttribute()

element.addEventListener()

window.content

window.onload

window.dump()

window.scrollTo()

ReactkeepsacopyoftheDOMrepresentation,forwhatconcernstheReactrendering:theVirtualDOM

TheVirtualDOMExplained

EverytimetheDOMchanges,thebrowserhastodotwointensiveoperations:repaint(visualorcontentchangestoanelementthatdonotaffectthelayoutandpositioningrelativetootherelements)andreflow(recalculatethelayoutofaportionofthepage-orthewholepagelayout).

ReactusesaVirtualDOMtohelpthebrowseruselessresourceswhenchangesneedtobedoneonapage.

TheVirtualDOM

60

Page 61: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Whenyoucall setState()onaComponent,specifyingastatedifferentthanthepreviousone,ReactmarksthatComponentasdirty.Thisiskey:ReactonlyupdateswhenaComponentchangesthestateexplicitly.

Whathappensnextis:

ReactupdatestheVirtualDOMrelativetothecomponentsmarkedasdirty(withsomeadditionalchecks,liketriggering shouldComponentUpdate())RunsthediffingalgorithmtoreconcilethechangesUpdatestherealDOM

WhyistheVirtualDOMhelpful:batching

ThekeythingisthatReactbatchesmuchofthechangesandperformsauniqueupdatetotherealDOM,bychangingalltheelementsthatneedtobechangedatthesametime,sotherepaintandreflowthebrowsermustperformtorenderthechangesareexecutedjustonce.

TheVirtualDOM

61

Page 62: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

UnidirectionalDataFlowWorkingwithReactyoumightencounterthetermUnidirectionalDataFlow.Whatdoesitmean?

UnidirectionalDataFlowisnotaconceptuniquetoReact,butasaJavaScriptdeveloperthismightbethefirsttimeyouhearit.

Ingeneralthisconceptmeansthatdatahasone,andonlyone,waytobetransferredtootherpartsoftheapplication.

InReactthismeansthat:

stateispassedtotheviewandtochildcomponentsactionsaretriggeredbytheviewactionscanupdatethestatethestatechangeispassedtotheviewandtochildcomponents

Theviewisaresultoftheapplicationstate.Statecanonlychangewhenactionshappen.Whenactionshappen,thestateisupdated.

UnidirectionalDataFlow

62

Page 63: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thankstoone-waybindings,datacannotflowintheoppositeway(aswouldhappenwithtwo-waybindings,forexample),andthishassomekeyadvantages:

it'slesserrorprone,asyouhavemorecontroloveryourdatait'seasiertodebug,asyouknowwhatiscomingfromwhereit'smoreefficient,asthelibraryalreadyknowswhattheboundariesareofeachpartofthesystem

AstateisalwaysownedbyoneComponent.Anydatathat'saffectedbythisstatecanonlyaffectComponentsbelowit:itschildren.

ChangingstateonaComponentwillneveraffectitsparent,oritssiblings,oranyotherComponentintheapplication:justitschildren.

ThisisthereasonthatthestateisoftenmovedupintheComponenttree,sothatitcanbesharedbetweencomponentsthatneedtoaccessit.

UnidirectionalDataFlow

63

Page 64: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

JSXJSXisatechnologythatwasintroducedbyReact.Let'sdiveintoit

IntroductiontoJSXJSXisatechnologythatwasintroducedbyReact.

AlthoughReactcanworkcompletelyfinewithoutusingJSX,it'sanidealtechnologytoworkwithcomponents,soReactbenefitsalotfromJSX.

Atfirst,youmightthinkthatusingJSXislikemixingHTMLandJavaScript(andasyou'llseeCSS).

Butthisisnottrue,becausewhatyouarereallydoingwhenusingJSXsyntaxiswritingadeclarativesyntaxofwhatacomponentUIshouldbe.

Andyou'redescribingthatUInotusingstrings,butinsteadusingJavaScript,whichallowsyoutodomanynicethings.

AJSXprimerHereishowyoudefineah1tagcontainingastring:

constelement=<h1>Hello,world!</h1>

JSX

64

Page 65: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ItlookslikeastrangemixofJavaScriptandHTML,butinrealityit'sallJavaScript.

WhatlookslikeHTML,isactuallysyntacticsugarfordefiningcomponentsandtheirpositioninginsidethemarkup.

InsideaJSXexpression,attributescanbeinsertedveryeasily:

constmyId='test'

constelement=<h1id={myId}>Hello,world!</h1>

Youjustneedtopayattentionwhenanattributehasadash( -)whichisconvertedtocamelCasesyntaxinstead,andthese2specialcases:

classbecomes classNameforbecomes htmlFor

becausetheyarereservedwordsinJavaScript.

Here'saJSXsnippetthatwrapstwocomponentsintoa divtag:

<div>

<BlogPostsList/>

<Sidebar/>

</div>

Atagalwaysneedstobeclosed,becausethisismoreXMLthanHTML(ifyouremembertheXHTMLdays,thiswillbefamiliar,butsincethentheHTML5loosesyntaxwon).Inthiscaseaself-closingtagisused.

NoticehowIwrappedthe2componentsintoa div.Why?Becausetherender()functioncanonlyreturnasinglenode,soincaseyouwanttoreturn2siblings,justaddaparent.Itcanbeanytag,notjust div.

TranspilingJSXAbrowsercannotexecuteJavaScriptfilescontainingJSXcode.TheymustbefirsttransformedtoregularJS.

How?Bydoingaprocesscalledtranspiling.

WealreadysaidthatJSXisoptional,becausetoeveryJSXline,acorrespondingplainJavaScriptalternativeisavailable,andthat'swhatJSXistranspiledto.

Forexamplethefollowingtwoconstructsareequivalent:

JSX

65

Page 66: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PlainJS

ReactDOM.render(

React.DOM.div(

{id:'test'},

React.DOM.h1(null,'Atitle'),

React.DOM.p(null,'Aparagraph')

),

document.getElementById('myapp')

)

JSX

ReactDOM.render(

<divid="test">

<h1>Atitle</h1>

<p>Aparagraph</p>

</div>,

document.getElementById('myapp')

)

Thisverybasicexampleisjustthestartingpoint,butyoucanalreadyseehowmorecomplicatedtheplainJSsyntaxiscomparedtousingJSX.

AtthetimeofwritingthemostpopularwaytoperformthetranspilationistouseBabel,whichisthedefaultoptionwhenrunning create-react-app,soifyouuseityoudon'thavetoworry,everythinghappensunderthehoodforyou.

Ifyoudon'tuse create-react-appyouneedtosetupBabelyourself.

JSinJSXJSXacceptsanykindofJavaScriptmixedintoit.

WheneveryouneedtoaddsomeJS,justputitinsidecurlybraces {}.Forexamplehere'showtouseaconstantvaluedefinedelsewhere:

constparagraph='Aparagraph'

ReactDOM.render(

<divid="test">

<h1>Atitle</h1>

<p>{paragraph}</p>

</div>,

document.getElementById('myapp')

)

Thisisabasicexample.CurlybracesacceptanyJScode:

JSX

66

Page 67: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

constparagraph='Aparagraph'

ReactDOM.render(

<table>

{rows.map((row,i)=>{

return<tr>{row.text}</tr>

})}

</div>,

document.getElementById('myapp')

)

AsyoucanseewenestedJavaScriptinsideJSXdefinedinsideJavaScriptnestedinJSX.Youcangoasdeepasyouneed.

HTMLinJSXJSXresemblesHTMLalot,butit'sactuallyXMLsyntax.

IntheendyourenderHTML,soyouneedtoknowafewdifferencesbetweenhowyouwoulddefinesomethingsinHTML,andhowyoudefinetheminJSX.

Youneedtoclosealltags

JustlikeinXHTML,ifyouhaveeverusedit,youneedtoclosealltags:nomore <br>butinsteadusetheself-closingtag: <br/>(thesamegoesforothertags)

camelCaseisthenewstandard

InHTMLyou'llfindattributeswithoutanycase(e.g. onchange).InJSX,theyarerenamedtotheircamelCaseequivalent:

onchange=> onChangeonclick=> onClickonsubmit=> onSubmit

classbecomes className

DuetothefactthatJSXisJavaScript,and classisareservedword,youcan'twrite

<pclass="description">

butyouneedtouse

<pclassName="description">

JSX

67

Page 68: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thesameappliesto forwhichistranslatedto htmlFor.

Thestyleattributechangesitssemantics

The styleattributeinHTMLallowstospecifyinlinestyle.InJSXitnolongeracceptsastring,andinCSSinReactyou'llseewhyit'saveryconvenientchange.

Forms

FormfieldsdefinitionandeventsarechangedinJSXtoprovidemoreconsistencyandutility.

FormsinJSXgoesintomoredetailsonforms.

CSSinReactJSXprovidesacoolwaytodefineCSS.

IfyouhavealittleexperiencewithHTMLinlinestyles,atfirstglanceyou'llfindyourselfpushedback10or15years,toaworldwhereinlineCSSwascompletelynormal(nowadaysit'sdemonizedandusuallyjusta"quickfix"go-tosolution).

JSXstyleisnotthesamething:firstofall,insteadofacceptingastringcontainingCSSproperties,theJSX styleattributeonlyacceptsanobject.Thismeansyoudefinepropertiesinanobject:

vardivStyle={

color:'white'

}

ReactDOM.render(<divstyle={divStyle}>HelloWorld!</div>,mountNode)

or

ReactDOM.render(<divstyle={{color:'white'}}>HelloWorld!</div>,mountNode)

TheCSSvaluesyouwriteinJSXareslightlydifferentfromplainCSS:

thekeyspropertynamesarecamelCasedvaluesarejuststringsyouseparateeachtuplewithacomma

WhyisthispreferredoverplainCSS/SASS/LESS?

JSX

68

Page 69: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CSSisanunsolvedproblem.Sinceitsinception,dozensoftoolsarounditroseandthenfell.ThemainproblemwithJSisthatthereisnoscopingandit'seasytowriteCSSthatisnotenforcedinanyway,thusa"quickfix"canimpactelementsthatshouldnotbetouched.

JSXallowscomponents(definedinReactforexample)tocompletelyencapsulatetheirstyle.

Isthisthego-tosolution?

InlinestylesinJSXaregooduntilyouneedto

1. writemediaqueries2. styleanimations3. referencepseudoclasses(e.g. :hover)4. referencepseudoelements(e.g. ::first-letter)

Inshort,theycoverthebasics,butit'snotthefinalsolution.

FormsinJSXJSXaddssomechangestohowHTMLformswork,withthegoalofmakingthingseasierforthedeveloper.

valueand defaultValue

The valueattributealwaysholdsthecurrentvalueofthefield.

The defaultValueattributeholdsthedefaultvaluethatwassetwhenthefieldwascreated.

ThishelpssolvesomeweirdbehaviorofregularDOMinteractionwheninspectinginput.valueand input.getAttribute('value')returningonethecurrentvalueandonetheoriginaldefaultvalue.

Thisalsoappliestothe textareafield,e.g.

<textarea>Sometext</textarea>

butinstead

<textareadefaultValue={'Sometext'}/>

For selectfields,insteadofusing

<select>

JSX

69

Page 70: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

<optionvalue="x"selected>

...

</option>

</select>

use

<selectdefaultValue="x">

<optionvalue="x">...</option>

</select>

AmoreconsistentonChange

Passingafunctiontothe onChangeattributeyoucansubscribetoeventsonformfields.

Itworksconsistentlyacrossfields,even radio, selectand checkboxinputfieldsfireaonChangeevent.

onChangealsofireswhentypingacharacterintoan inputor textareafield.

JSXautoescapesTomitigatetheeverpresentriskofXSSexploits,JSXforcesautomaticescapinginexpressions.

ThismeansthatyoumightrunintoissueswhenusinganHTMLentityinastringexpression.

Youexpectthefollowingtoprint ©2017:

<p>{'&copy;2017'}</p>

Butit'snot,it'sprinting &copy;2017becausethestringisescaped.

Tofixthisyoucaneithermovetheentitiesoutsidetheexpression:

<p>&copy;2017</p>

orbyusingaconstantthatprintstheUnicoderepresentationcorrespondingtotheHTMLentityyouneedtoprint:

<p>{'\u00A92017'}</p>

JSX

70

Page 71: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

WhitespaceinJSXToaddwhitespaceinJSXthereare2rules:

Horizontalwhitespaceistrimmedto1

Ifyouhavewhitespacebetweenelementsinthesameline,it'salltrimmedto1whitespace.

<p>Somethingbecomesthis</p>

becomes

<p>Somethingbecomesthis</p>

Verticalwhitespaceiseliminated

<p>

Something

becomes

this

</p>

becomes

<p>Somethingbecomesthis</p>

Tofixthisproblemyouneedtoexplicitlyaddwhitespace,byaddingaspaceexpressionlikethis:

<p>

Something

{''}becomes

{''}this

</p>

orbyembeddingthestringinaspaceexpression:

<p>

Something

{'becomes'}

this

</p>

JSX

71

Page 72: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

AddingcommentsinJSXYoucanaddcommentstoJSXbyusingthenormalJavaScriptcommentsinsideanexpression:

<p>

{/*acomment*/}

{

//anothercomment

}

</p>

SpreadattributesInJSXacommonoperationisassigningvaluestoattributes.

Insteadofdoingitmanually,e.g.

<div>

<BlogPosttitle={data.title}date={data.date}/>

</div>

youcanpass

<div>

<BlogPost{...data}/>

</div>

andthepropertiesofthe dataobjectwillbeusedasattributesautomatically,thankstotheES6spreadoperator

HowtoloopinJSXIfyouhaveasetofelementsyouneedtoloopupontogenerateaJSXpartial,youcancreatealoop,andthenaddJSXtoanarray:

constelements=[]//..somearray

constitems=[]

for(const[index,value]ofelements.entries(){

items.push(<Elementkey={index}/>)

}

JSX

72

Page 73: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

NowwhenrenderingtheJSXyoucanembedthe itemsarraysimplybywrappingitincurlybraces:

constelements=['one','two','three'];

constitems=[]

for(const[index,value]ofelements.entries(){

items.push(<likey={index}>{value}</li>)

}

return(

<div>

{items}

</div>

)

YoucandothesamedirectlyintheJSX,using mapinsteadofafor-ofloop:

constelements=['one','two','three'];

return(

<ul>

{elements.map((value,index)=>{

return<likey={index}>{value}</li>

})}

</ul>

)

JSX

73

Page 74: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ComponentsAbriefintroductiontoReactComponents

Acomponentisoneisolatedpieceofinterface.ForexampleinatypicalbloghomepageyoumightfindtheSidebarcomponent,andtheBlogPostsListcomponent.Theyareinturncomposedofcomponentsthemselves,soyoucouldhavealistofBlogpostcomponents,eachforeveryblogpost,andeachwithitsownpeculiarproperties.

Reactmakesitverysimple:everythingisacomponent.

EvenplainHTMLtagsarecomponentontheirown,andtheyareaddedbydefault.

Thenext2linesareequivalent,theydothesamething.OnewithJSX,onewithout,byinjecting <h1>HelloWorld!</h1>intoanelementwithid app.

importReactfrom'react'

importReactDOMfrom'react-dom'

ReactDOM.render(<h1>HelloWorld!</h1>,document.getElementById('app'))

ReactDOM.render(

React.DOM.h1(null,'HelloWorld!'),

document.getElementById('app')

)

See, React.DOMexposedusan h1component.WhichotherHTMLtagsareavailable?Allofthem!Youcaninspectwhat React.DOMoffersbytypingitintheBrowserConsole:

Components

74

Page 75: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

(thelistislonger)

Thebuilt-incomponentsarenice,butyou'llquicklyoutgrowthem.WhatReactexcelsinislettinguscomposeaUIbycomposingcustomcomponents.

CustomcomponentsThereare2waystodefineacomponentinReact.

Afunctioncomponent:

constBlogPostExcerpt=()=>{

return(

<div>

<h1>Title</h1>

<p>Description</p>

</div>

)

}

Aclasscomponent:

importReact,{Component}from'react'

classBlogPostExcerptextendsComponent{

render(){

return(

<div>

<h1>Title</h1>

<p>Description</p>

Components

75

Page 76: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

</div>

)

}

}

Upuntilrecently,classcomponentsweretheonlywaytodefineacomponentthathaditsownstate,andcouldaccessthelifecyclemethodssoyoucoulddothingswhenthecomponentwasfirstrendered,updatedorremoved.

ReactHookschangedthis,soourfunctioncomponentsarenowmuchmorepowerfulthaneverandIbelievewe'llseefewerandfewerclasscomponentsinthefuture,althoughitwillstillbeperfectlyvalidwaytocreatecomponents.

Thereisalsoathirdsyntaxwhichusesthe ES5syntax,withouttheclasses:

importReactfrom'react'

React.createClass({

render(){

return(

<div>

<h1>Title</h1>

<p>Description</p>

</div>

)

}

})

You'llrarelyseethisinmodern, >ES6codebases.

Components

76

Page 77: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

StateHowtointeractwiththestateofyourcomponents

Settingthedefaultstate

IntheComponentconstructor,initialize this.state.ForexampletheBlogPostExcerptcomponentmighthavea clickedstate:

classBlogPostExcerptextendsComponent{

constructor(props){

super(props)

this.state={clicked:false}

}

render(){

return(

<div>

<h1>Title</h1>

<p>Description</p>

</div>

)

}

}

Accessingthestate

Theclickedstatecanbeaccessedbyreferencing this.state.clicked:

classBlogPostExcerptextendsComponent{

constructor(props){

super(props)

this.state={clicked:false}

}

render(){

return(

<div>

<h1>Title</h1>

<p>Description</p>

<p>Clicked:{this.state.clicked}</p>

</div>

)

}

}

State

77

Page 78: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Mutatingthestate

Astateshouldneverbemutatedbyusing

this.state.clicked=true

Instead,youshouldalwaysuse setState()instead,passingitanobject:

this.setState({clicked:true})

Theobjectcancontainasubset,orasuperset,ofthestate.Onlythepropertiesyoupasswillbemutated,theonesomittedwillbeleftintheircurrentstate.

WhyyoushouldalwaysusesetState()

Thereasonisthatusingthismethod,Reactknowsthatthestatehaschanged.ItwillthenstarttheseriesofeventsthatwillleadtotheComponentbeingre-rendered,alongwithanyDOMupdate.

UnidirectionalDataFlow

AstateisalwaysownedbyoneComponent.Anydatathat'saffectedbythisstatecanonlyaffectComponentsbelowit:itschildren.

ChangingthestateonaComponentwillneveraffectitsparent,oritssiblings,oranyotherComponentintheapplication:justitschildren.

ThisisthereasonthestateisoftenmovedupintheComponenttree.

MovingtheStateUpintheTree

BecauseoftheUnidirectionalDataFlowrule,iftwocomponentsneedtosharestate,thestateneedstobemoveduptoacommonancestor.

Manytimestheclosestancestoristhebestplacetomanagethestate,butit'snotamandatoryrule.

Thestateispasseddowntothecomponentsthatneedthatvalueviaprops:

classConverterextendsReact.Component{

constructor(props){

super(props)

this.state={currency:'€'}

}

State

78

Page 79: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

render(){

return(

<div>

<Displaycurrency={this.state.currency}/>

<CurrencySwitchercurrency={this.state.currency}/>

</div>

)

}

}

Thestatecanbemutatedbyachildcomponentbypassingamutatingfunctiondownasaprop:

classConverterextendsReact.Component{

constructor(props){

super(props)

this.state={currency:'€'}

}

handleChangeCurrency=event=>{

this.setState({currency:this.state.currency==='€'?'$':'€'})

}

render(){

return(

<div>

<Displaycurrency={this.state.currency}/>

<CurrencySwitcher

currency={this.state.currency}

handleChangeCurrency={this.handleChangeCurrency}

/>

</div>

)

}

}

constCurrencySwitcher=props=>{

return(

<buttononClick={props.handleChangeCurrency}>

Currentcurrencyis{props.currency}.Changeit!

</button>

)

}

constDisplay=props=>{

return<p>Currentcurrencyis{props.currency}.</p>

}

State

79

Page 80: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

State

80

Page 81: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PropsHowtousepropstopassdataaroundyourReactcomponents

PropsishowComponentsgettheirproperties.Startingfromthetopcomponent,everychildcomponentgetsitspropsfromtheparent.Inafunctioncomponent,propsisallitgetspassed,andtheyareavailablebyadding propsasthefunctionargument:

constBlogPostExcerpt=props=>{

return(

<div>

<h1>{props.title}</h1>

<p>{props.description}</p>

</div>

)

}

Inaclasscomponent,propsarepassedbydefault.Thereisnoneedtoaddanythingspecial,andtheyareaccessibleas this.propsinaComponentinstance.

importReact,{Component}from'react'

classBlogPostExcerptextendsComponent{

render(){

return(

<div>

<h1>{this.props.title}</h1>

<p>{this.props.description}</p>

</div>

)

}

}

Passingpropsdowntochildcomponentsisagreatwaytopassvaluesaroundinyourapplication.Acomponenteitherholdsdata(hasstate)orreceivesdatathroughitsprops.

Itgetscomplicatedwhen:

youneedtoaccessthestateofacomponentfromachildthat'sseverallevelsdown(allthepreviouschildrenneedtoactasapass-through,eveniftheydonotneedtoknowthestate,complicatingthings)youneedtoaccessthestateofacomponentfromacompletelyunrelatedcomponent.

Defaultvaluesforprops

Props

81

Page 82: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Ifanyvalueisnotrequiredweneedtospecifyadefaultvalueforitifit'smissingwhentheComponentisinitialized.

BlogPostExcerpt.propTypes={

title:PropTypes.string,

description:PropTypes.string

}

BlogPostExcerpt.defaultProps={

title:'',

description:''

}

SometoolinglikeESLinthavetheabilitytoenforcedefiningthedefaultPropsforaComponentwithsomepropTypesnotexplicitlyrequired.

HowpropsarepassedWheninitializingacomponent,passthepropsinawaysimilartoHTMLattributes:

constdesc='Adescription'

//...

<BlogPostExcerpttitle="Ablogpost"description={desc}/>

Wepassedthetitleasaplainstring(somethingwecanonlydowithstrings!),anddescriptionasavariable.

ChildrenAspecialpropis children.Thatcontainsthevalueofanythingthatispassedinthe bodyofthecomponent,forexample:

<BlogPostExcerpttitle="Ablogpost"description="{desc}">

Something

</BlogPostExcerpt>

Inthiscase,inside BlogPostExcerptwecouldaccess"Something"bylookingupthis.props.children.

WhilePropsallowaComponenttoreceivepropertiesfromitsparent,tobe"instructed"toprintsomedataforexample,stateallowsacomponenttotakeonlifeitself,andbeindependentofthesurroundingenvironment.

Props

82

Page 83: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Props

83

Page 84: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PresentationalvscontainercomponentsThedifferencebetweenPresentationalandContainerComponentsinReact

InReactcomponentsareoftendividedinto2bigbuckets:presentationalcomponentsandcontainercomponents.

Eachofthosehavetheiruniquecharacteristics.

Presentationalcomponentsaremostlyconcernedwithgeneratingsomemarkuptobeoutputted.

Theydon'tmanageanykindofstate,exceptforstaterelatedthethepresentation

Containercomponentsaremostlyconcernedwiththe"backend"operations.

Theymighthandlethestateofvarioussub-components.Theymightwrapseveralpresentationalcomponents.TheymightinterfacewithRedux.

Asawaytosimplifythedistinction,wecansaypresentationalcomponentsareconcernedwiththelook,containercomponentsareconcernedwithmakingthingswork.

Forexample,thisisapresentationalcomponent.Itgetsdatafromitsprops,andjustfocusesonshowinganelement:

constUsers=props=>(

<ul>

{props.users.map(user=>(

<li>{user}</li>

))}

</ul>

)

Ontheotherhandthisisacontainercomponent.Itmanagesandstoresitsowndata,andusesthepresentationalcomponenttodisplayit.

classUsersContainerextendsReact.Component{

constructor(){

this.state={

users:[]

}

}

componentDidMount(){

axios.get('/users').then(users=>

this.setState({users:users}))

)

}

Presentationalvscontainercomponents

84

Page 85: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

render(){

return<Usersusers={this.state.users}/>

}

}

Presentationalvscontainercomponents

85

Page 86: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

StatevsPropsWhat'sthedifferencebetweenstateandpropsinReact?

InaReactcomponent,propsarevariablespassedtoitbyitsparentcomponent.Stateontheotherhandisstillvariables,butdirectlyinitializedandmanagedbythecomponent.

Thestatecanbeinitializedbyprops.

Forexample,aparentcomponentmightincludeachildcomponentbycalling

<ChildComponent/>

Theparentcanpassapropbyusingthissyntax:

<ChildComponentcolor=green/>

InsidetheChildComponentconstructorwecouldaccesstheprop:

classChildComponentextendsReact.Component{

constructor(props){

super(props)

console.log(props.color)

}

}

andanyothermethodinthisclasscanreferencethepropsusing this.props.

Propscanbeusedtosettheinternalstatebasedonapropvalueintheconstructor,likethis:

classChildComponentextendsReact.Component{

constructor(props){

super(props)

this.state.colorName=props.color

}

}

Ofcourseacomponentcanalsoinitializethestatewithoutlookingatprops.

Inthiscasethere'snothingusefulgoingon,butimaginedoingsomethingdifferentbasedonthepropvalue,probablysettingastatevalueisbest.

Propsshouldneverbechangedinachildcomponent,soifthere'ssomethinggoingonthatalterssomevariable,thatvariableshouldbelongtothecomponentstate.

StatevsProps

86

Page 87: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Propsarealsousedtoallowchildcomponentstoaccessmethodsdefinedintheparentcomponent.Thisisagoodwaytocentralizemanagingthestateintheparentcomponent,andavoidchildrentohavetheneedtohavetheirownstate.

Mostofyourcomponentswilljustdisplaysomekindofinformationbasedonthepropstheyreceived,andstaystateless.

StatevsProps

87

Page 88: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PropTypesHowtousePropTypestosettherequiredtypeofaprop

SinceJavaScriptisadynamicallytypedlanguage,wedon'treallyhaveawaytoenforcethetypeofavariableatcompiletime,andifwepassinvalidtypes,theywillfailatruntimeorgiveweirdresultsifthetypesarecompatiblebutnotwhatweexpect.

FlowandTypeScripthelpalot,butReacthasawaytodirectlyhelpwithpropstypes,andevenbeforerunningthecode,ourtools(editors,linters)candetectwhenwearepassingthewrongvalues:

importPropTypesfrom'prop-types'

importReactfrom'react'

classBlogPostExcerptextendsComponent{

render(){

return(

<div>

<h1>{this.props.title}</h1>

<p>{this.props.description}</p>

</div>

)

}

}

BlogPostExcerpt.propTypes={

title:PropTypes.string,

description:PropTypes.string

}

exportdefaultBlogPostExcerpt

Whichtypescanweuse

Thesearethefundamentaltypeswecanaccept:

PropTypes.arrayPropTypes.boolPropTypes.funcPropTypes.numberPropTypes.objectPropTypes.stringPropTypes.symbol

Wecanacceptoneoftwotypes:

PropTypes

88

Page 89: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PropTypes.oneOfType([

PropTypes.string,

PropTypes.number

]),

Wecanacceptoneofmanyvalues:

PropTypes.oneOf(['Test1','Test2']),

Wecanacceptaninstanceofaclass:

PropTypes.instanceOf(Something)

WecanacceptanyReactnode:

PropTypes.node

orevenanytypeatall:

PropTypes.any

Arrayshaveaspecialsyntaxthatwecanusetoacceptanarrayofaparticulartype:

PropTypes.arrayOf(PropTypes.string)

Objects,wecancomposeanobjectpropertiesbyusing

PropTypes.shape({

color:PropTypes.string,

fontSize:PropTypes.number

})

Requiringproperties

Appending isRequiredtoanyPropTypesoptionwillcauseReacttoreturnanerrorifthatpropertyismissing:

PropTypes.arrayOf(PropTypes.string).isRequired,

PropTypes.string.isRequired,

PropTypes

89

Page 90: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PropTypes

90

Page 91: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

FragmentHowtouseReact.FragmenttocreateinvisibleHTMLtags

NoticehowIwrapreturnvaluesina div.Thisisbecauseacomponentcanonlyreturnonesingleelement,andifyouwantmorethanone,youneedtowrapitwithanothercontainertag.

Thishowevercausesanunnecessary divintheoutput.YoucanavoidthisbyusingReact.Fragment:

importReact,{Component}from'react'

classBlogPostExcerptextendsComponent{

render(){

return(

<React.Fragment>

<h1>{this.props.title}</h1>

<p>{this.props.description}</p>

</React.Fragment>

)

}

}

whichalsohasaveryniceshorthandsyntax <></>thatissupportedonlyinrecentreleases(andBabel7+):

importReact,{Component}from'react'

classBlogPostExcerptextendsComponent{

render(){

return(

<>

<h1>{this.props.title}</h1>

<p>{this.props.description}</p>

</>

)

}

}

Fragment

91

Page 92: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

EventsLearnhowtointeractwitheventsinaReactapplication

Reactprovidesaneasywaytomanageevents.Preparetosaygoodbyeto addEventListener.

InthepreviousarticleabouttheStateyousawthisexample:

constCurrencySwitcher=props=>{

return(

<buttononClick={props.handleChangeCurrency}>

Currentcurrencyis{props.currency}.Changeit!

</button>

)

}

Ifyou'vebeenusingJavaScriptforawhile,thisisjustlikeplainoldJavaScripteventhandlers,exceptthatthistimeyou'redefiningeverythinginJavaScript,notinyourHTML,andyou'repassingafunction,notastring.

TheactualeventnamesarealittlebitdifferentbecauseinReactyouusecamelCaseforeverything,so onclickbecomes onClick, onsubmitbecomes onSubmit.

Forreference,thisisoldschoolHTMLwithJavaScripteventsmixedin:

<buttononclick="handleChangeCurrency()">...</button>

Eventhandlers

It'saconventiontohaveeventhandlersdefinedasmethodsontheComponentclass:

classConverterextendsReact.Component{

handleChangeCurrency=event=>{

this.setState({currency:this.state.currency==='€'?'$':'€'})

}

}

Allhandlersreceiveaneventobjectthatadheres,cross-browser,totheW3CUIEventsspec.

Bind thisinmethods

Don'tforgettobindmethods.ThemethodsofES6classesbydefaultarenotbound.Whatthismeansisthat thisisnotdefinedunlessyoudefinemethodsasarrowfunctions:

Events

92

Page 93: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

classConverterextendsReact.Component{

handleClick=e=>{

/*...*/

}

//...

}

whenusingthethepropertyinitializersyntaxwithBabel(enabledbydefaultin create-react-app),otherwiseyouneedtobinditmanuallyintheconstructor:

classConverterextendsReact.Component{

constructor(props){

super(props)

this.handleClick=this.handleClick.bind(this)

}

handleClick(e){}

}

Theeventsreference

Therearelotsofeventssupported,here'sasummarylist.

Clipboard

onCopyonCutonPaste

Composition

onCompositionEndonCompositionStartonCompositionUpdate

Keyboard

onKeyDownonKeyPressonKeyUp

Focus

onFocus

Events

93

Page 94: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

onBlur

Form

onChangeonInputonSubmit

Mouse

onClickonContextMenuonDoubleClickonDragonDragEndonDragEnteronDragExitonDragLeaveonDragOveronDragStartonDroponMouseDownonMouseEnteronMouseLeaveonMouseMoveonMouseOutonMouseOveronMouseUp

Selection

onSelect

Touch

onTouchCancelonTouchEndonTouchMoveonTouchStart

UI

Events

94

Page 95: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

onScroll

MouseWheel

onWheel

Media

onAbortonCanPlayonCanPlayThroughonDurationChangeonEmptiedonEncryptedonEndedonErroronLoadedDataonLoadedMetadataonLoadStartonPauseonPlayonPlayingonProgressonRateChangeonSeekedonSeekingonStalledonSuspendonTimeUpdateonVolumeChangeonWaiting

Image

onLoadonError

Animation

onAnimationStartonAnimationEnd

Events

95

Page 96: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

onAnimationIteration

Transition

onTransitionEnd

Events

96

Page 97: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

LifecycleeventsFindouttheReactLifecycleeventsandhowyoucanusethem

Reactclasscomponentscanhavehooksforseverallifecycleevents.

Hooksallowfunctioncomponentstoaccessthemtoo,inadifferentway.

Duringthelifetimeofacomponent,there'saseriesofeventsthatgetscalled,andtoeacheventyoucanhookandprovidecustomfunctionality.

Whathookisbestforwhatfunctionalityissomethingwe'regoingtoseehere.

First,thereare3phasesinaReactcomponentlifecycle:

MountingUpdatingUnmounting

Let'sseethose3phasesindetailandthemethodsthatgetcalledforeach.

MountingWhenmountingyouhave4lifecyclemethodsbeforethecomponentismountedintheDOM:the constructor, getDerivedStateFromProps, renderand componentDidMount.

Constructor

Theconstructoristhefirstmethodthatiscalledwhenmountingacomponent.

Youusuallyusetheconstructortosetuptheinitialstateusing this.state=....

getDerivedStateFromProps()

Whenthestatedependsonprops, getDerivedStateFromPropscanbeusedtoupdatethestatebasedonthepropsvalue.

ItwasaddedinReact16.3,aimingtoreplacethe componentWillReceivePropsdeprecatedmethod.

Inthismethodyouhaven'taccessto thisasit'sastaticmethod.

It'sapuremethod,soitshouldnotcausesideeffectsandshouldreturnthesameoutputwhencalledmultipletimeswiththesameinput.

Lifecycleevents

97

Page 98: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Returnsanobjectwiththeupdatedelementsofthestate(ornullifthestatedoesnotchange)

render()

Fromtherender()methodyoureturntheJSXthatbuildsthecomponentinterface.

It'sapuremethod,soitshouldnotcausesideeffectsandshouldreturnthesameoutputwhencalledmultipletimeswiththesameinput.

componentDidMount()

ThismethodistheonethatyouwillusetoperformAPIcalls,orprocessoperationsontheDOM.

UpdatingWhenupdatingyouhave5lifecyclemethodsbeforethecomponentismountedintheDOM:the getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdateandcomponentDidUpdate.

getDerivedStateFromProps()

Seetheabovedescriptionforthismethod.

shouldComponentUpdate()

Thismethodreturnsaboolean, trueor false.YouusethismethodtotellReactifitshouldgoonwiththererendering,anddefaultsto true.Youwillreturn falsewhenrerenderingisexpensiveandyouwanttohavemorecontrolonwhenthishappens.

render()

Seetheabovedescriptionforthismethod.

getSnapshotBeforeUpdate()

Inthismethodyouhaveaccesstothepropsandstateofthepreviousrender,andofthecurrentrender.

Itsusecasesareveryniche,andit'sprobablytheonethatyouwilluseless.

Lifecycleevents

98

Page 99: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

componentDidUpdate()

ThismethodiscalledwhenthecomponenthasbeenupdatedintheDOM.Usethistorunany3rdpartyDOMAPIorcallAPIsthatmustbeupdatedwhentheDOMchanges.

Itcorrespondstothe componentDidMount()methodfromthemountingphase.

UnmountingInthisphaseweonlyhaveonemethod, componentWillUnmount.

componentWillUnmount()

ThemethodiscalledwhenthecomponentisremovedfromtheDOM.Usethistodoanysortofcleanupyouneedtoperform.

LegacyIfyouareworkingonanappthatuses componentWillMount, componentWillReceivePropsorcomponentWillUpdate,thoseweredeprecatedinReact16.3andyoushouldmigratetootherlifecyclemethods.

Lifecycleevents

99

Page 100: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

HandlingformsHowtohandleformsinaReactapplication

FormsareoneofthefewHTMLelementsthatareinteractivebydefault.

Theyweredesignedtoallowtheusertointeractwithapage.

Commonusesofforms?

SearchContactformsShoppingcartscheckoutLoginandregistrationandmore!

UsingReactwecanmakeourformsmuchmoreinteractiveandlessstatic.

TherearetwomainwaysofhandlingformsinReact,whichdifferonafundamentallevel:howdataismanaged.

ifthedataishandledbytheDOM,wecallthemuncontrolledcomponents

Handlingforms

100

Page 101: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ifthedataishandledbythecomponentswecallthemcontrolledcomponents

Asyoucanimagine,controlledcomponentsiswhatyouwillusemostofthetime.Thecomponentstateisthesinglesourceoftruth,ratherthantheDOM.Someformfieldsareinherentlyuncontrolledbecauseoftheirbehavior,likethe <inputtype="file">field.

Whenanelementstatechangesinaformfieldmanagedbyacomponent,wetrackitusingtheonChangeattribute.

classFormextendsReact.Component{

constructor(props){

super(props)

this.state={username:''}

}

handleChange(event){}

render(){

return(

<form>

Username:

<input

type="text"

value={this.state.username}

onChange={this.handleChange}

/>

</form>

)

}

}

Inordertosetthenewstate,wemustbind thistothe handleChangemethod,otherwisethisisnotaccessiblefromwithinthatmethod:

classFormextendsReact.Component{

constructor(props){

super(props)

this.state={username:''}

this.handleChange=this.handleChange.bind(this)

}

handleChange(event){

this.setState({value:event.target.value})

}

render(){

return(

<form>

<input

type="text"

value={this.state.username}

onChange={this.handleChange}

Handlingforms

101

Page 102: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

/>

</form>

)

}

}

Similarly,weusethe onSubmitattributeontheformtocallthe handleSubmitmethodwhentheformissubmitted:

classFormextendsReact.Component{

constructor(props){

super(props)

this.state={username:''}

this.handleChange=this.handleChange.bind(this)

this.handleSubmit=this.handleSubmit.bind(this)

}

handleChange(event){

this.setState({value:event.target.value})

}

handleSubmit(event){

alert(this.state.username)

event.preventDefault()

}

render(){

return(

<formonSubmit={this.handleSubmit}>

<input

type="text"

value={this.state.username}

onChange={this.handleChange}

/>

<inputtype="submit"value="Submit"/>

</form>

)

}

}

Validationinaformcanbehandledinthe handleChangemethod:youhaveaccesstotheoldvalueofthestate,andthenewone.Youcancheckthenewvalueandifnotvalidrejecttheupdatedvalue(andcommunicateitinsomewaytotheuser).

HTMLFormsareinconsistent.Theyhavealonghistory,anditshows.Reacthowevermakesthingsmoreconsistentforus,andyoucanget(andupdate)fieldsusingits valueattribute.

Here'sa textarea,forexample:

<textareavalue={this.state.address}onChange={this.handleChange}/>

Handlingforms

102

Page 103: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thesamegoesforthe selecttag:

<selectvalue="{this.state.age}"onChange="{this.handleChange}">

<optionvalue="teen">Lessthan18</option>

<optionvalue="adult">18+</option>

</select>

Previouslywementionedthe <inputtype="file">field.Thatworksabitdifferently.

Inthiscaseyouneedtogetareferencetothefieldbyassigningthe refattributetoapropertydefinedintheconstructorwith React.createRef(),andusethattogetthevalueofitinthesubmithandler:

classFileInputextendsReact.Component{

constructor(props){

super(props)

this.curriculum=React.createRef()

this.handleSubmit=this.handleSubmit.bind(this)

}

handleSubmit(event){

alert(this.curriculum.current.files[0].name)

event.preventDefault()

}

render(){

return(

<formonSubmit={this.handleSubmit}>

<inputtype="file"ref={this.curriculum}/>

<inputtype="submit"value="Submit"/>

</form>

)

}

}

Thisistheuncontrolledcomponentsway.ThestateisstoredintheDOMratherthaninthecomponentstate(noticeweused this.curriculumtoaccesstheuploadedfile,andhavenottouchedthe state.

Iknowwhatyou'rethinking-beyondthosebasics,theremustbealibrarythatsimplifiesallthisformhandlingstuffandautomatesvalidation,errorhandlingandmore,right?Thereisagreatone,Formik(Formiktutorialcomingtomorrow!)

Handlingforms

103

Page 104: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ReferenceaDOMelementFindouthowtorefaDOMelementinReact

ReactisgreatatabstractingawaytheDOMfromyouwhenbuildingapps.

ButwhatifyouwanttoaccesstheDOMelementthataReactcomponentrepresents?

MaybeyouhavetoaddalibrarythatinteractsdirectlywiththeDOMlikeachartlibrary,maybeyouneedtocallsomeDOMAPI,oraddfocusonanelement.

Whateverthereasonis,agoodpracticeismakingsurethere'snootherwayofdoingsowithoutaccessingtheDOMdirectly.

IntheJSXofyourcomponent,youcanassignthereferenceoftheDOMelementtoacomponentpropertyusingthisattribute:

ref={el=>this.someProperty=el}

Putthisintocontext,forexamplewitha buttonelement:

<buttonref={el=>(this.button=el)}/>

buttonreferstoapropertyofthecomponent,whichcanthenbeusedbythecomponent'slifecyclemethods(orothermethods)tointeractwiththeDOM:

classSomeComponentextendsComponent{

render(){

return<buttonref={el=>(this.button=el)}/>

}

}

Inafunctioncomponentthemechanismisthesame,youjustavoidusing this(sinceitdoesnotpointtothecomponentinstance)anduseapropertyinstead:

functionSomeComponent(){

letbutton

return<buttonref={el=>(button=el)}/>

}

ReferenceaDOMelement

104

Page 105: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ReferenceaDOMelement

105

Page 106: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ServersiderenderingWhatisServerSideRendering?HowtodoitwithReact?

ServerSideRendering,alsocalledSSR,istheabilityofaJavaScriptapplicationtorenderontheserverratherthaninthebrowser.

Whywouldweeverwanttodoso?

itallowsyoursitetohaveafasterfirstpageloadtime,whichisthekeytoagooduserexperienceitisessentialforSEO:searchenginescannot(yet?)efficientlyandcorrectlyindexapplicationsthatexclusivelyrenderclient-side.DespitethelatestimprovementstoindexinginGoogle,thereareothersearchenginestoo,andGoogleisnotperfectatitinanycase.Also,Googlefavorssiteswithfastloadtimes,andhavingtoloadclient-sideisnotgoodforspeedit'sgreatwhenpeopleshareapageofyoursiteonsocialmedia,astheycaneasilygatherthemetadataneededtonicelysharethelink(images,title,description..)

WithoutServerSideRendering,allyourservershipsisanHTMLpagewithnobody,justsomescripttagsthatarethenusedbythebrowsertorendertheapplication.

Client-renderedappsaregreatatanysubsequentuserinteractionafterthefirstpageload.ServerSideRenderingallowsustogetthesweetspotinthemiddleofclient-renderedappsandbackend-renderedapps:thepageisgeneratedserver-side,butallinteractionswiththepageonceit'sbeenloadedarehandledclient-side.

HoweverServerSideRenderinghasitsdrawbacktoo:

it'sfairtosaythatasimpleSSRproofofconceptissimple,butthecomplexityofSSRcangrowwiththecomplexityofyourapplicationrenderingabigapplicationserver-sidecanbequiteresource-intensive,andunderheavyloaditcouldevenprovideaslowerexperiencethanclient-siderendering,sinceyouhaveasinglebottleneck

AverysimplisticexampleofwhatittakestoServer-SiderenderaReactappSSRsetupscangrowvery,verycomplexandmosttutorialswillbakeinRedux,ReactRouterandmanyotherconceptsfromthestart.

TounderstandhowSSRworks,let'sstartfromthebasicstoimplementaproofofconcept.

Serversiderendering

106

Page 107: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

FeelfreetoskipthisparagraphifyoujustwanttolookintothelibrariesthatprovideSSRandnotbotherwiththegroundwork

ToimplementbasicSSRwe'regoingtouseExpress.

IfyouarenewtoExpress,orneedsomecatch-up,checkoutmyfreeExpressHandbookhere:https://flaviocopes.com/page/ebooks/.

Warning:thecomplexityofSSRcangrowwiththecomplexityofyourapplication.ThisisthebareminimumsetuptorenderabasicReactapp.FormorecomplexneedsyoumightneedtodoabitmoreworkoralsocheckoutSSRlibrariesforReact.

IassumeyoustartedaReactappwith create-react-app.Ifyouarejusttrying,installonenowusing npxcreate-react-appssr.

Gotothemainappfolderwiththeterminal,thenrun:

npminstallexpress

Youhaveasetoffoldersinyourappdirectory.Createanewfoldercalled server,thengointoitandcreateafilenamed server.js.

Followingthe create-react-appconventions,theapplivesinthe src/App.jsfile.We'regoingtoloadthatcomponent,andrenderittoastringusingReactDOMServer.renderToString(),whichisprovidedby react-dom.

Yougetthecontentsofthe ./build/index.htmlfile,andreplacethe <divid="root"></div>placeholder,whichisthetagwheretheapplicationhooksbydefault,with ̀ <div

id="root">\${ReactDOMServer.renderToString(<App/>)}</div>.

Allthecontentinsidethe buildfolderisgoingtobeservedas-is,staticallybyExpress.

importpathfrom'path'

importfsfrom'fs'

importexpressfrom'express'

importReactfrom'react'

importReactDOMServerfrom'react-dom/server'

importAppfrom'../src/App'

constPORT=8080

constapp=express()

constrouter=express.Router()

constserverRenderer=(req,res,next)=>{

fs.readFile(path.resolve('./build/index.html'),'utf8',(err,data)=>{

if(err){

Serversiderendering

107

Page 108: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

console.error(err)

returnres.status(500).send('Anerroroccurred')

}

returnres.send(

data.replace(

'<divid="root"></div>',

`<divid="root">${ReactDOMServer.renderToString(<App/>)}</div>`

)

)

})

}

router.use('^/$',serverRenderer)

router.use(

express.static(path.resolve(__dirname,'..','build'),{maxAge:'30d'})

)

//telltheapptousetheaboverules

app.use(router)

//app.use(express.static('./build'))

app.listen(PORT,()=>{

console.log(`SSRrunningonport${PORT}`)

})

Now,intheclientapplication,inyour src/index.js,insteadofcalling ReactDOM.render():

ReactDOM.render(<App/>,document.getElementById('root'))

call ReactDOM.hydrate(),whichisthesamebuthastheadditionalabilitytoattacheventlistenerstoexistingmarkuponceReactloads:

ReactDOM.hydrate(<App/>,document.getElementById('root'))

AlltheNode.jscodeneedstobetranspiledbyBabel,asserver-sideNode.jscodedoesnotknowanythingaboutJSX,norESModules(whichweuseforthe includestatements).

Installthese3packages:

npminstall@babel/register@babel/preset-env@babel/preset-reactignore-stylesexpress

ignore-stylesisaBabelutilitythatwilltellittoignoreCSSfilesimportedusingthe importsyntax.

Let'screateanentrypointin server/index.js:

require('ignore-styles')

Serversiderendering

108

Page 109: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

require('@babel/register')({

ignore:[/(node_modules)/],

presets:['@babel/preset-env','@babel/preset-react']

})

require('./server')

BuildtheReactapplication,sothatthebuild/folderispopulated:

npmrunbuild

andlet'srunthis:

nodeserver/index.js

Isaidthisisasimplisticapproach,anditis:

itdoesnothandlerenderingimagescorrectlywhenusingimports,whichneedWebpackinordertowork(andwhichcomplicatestheprocessalot)itdoesnothandlepageheadermetadata,whichisessentialforSEOandsocialsharingpurposes(amongotherthings)

Sowhilethisisagoodexampleofusing ReactDOMServer.renderToString()andReactDOM.hydratetogetthisbasicserver-siderendering,it'snotenoughforrealworldusage.

ServerSideRenderingusinglibrariesSSRishardtodoright,andReacthasnode-factowaytoimplementit.

It'sstillverymuchdebatableifit'sworththetrouble,complicationandoverheadtogetthebenefits,ratherthanusingadifferenttechnologytoservethosepages.ThisdiscussiononReddithaslotsofopinionsinthatregard.

WhenServerSideRenderingisanimportantmatter,mysuggestionistorelyonpre-madelibrariesandtoolsthathavehadthisgoalinmindsincethebeginning.

Inparticular,IsuggestNext.jsandGatsby,twoprojectswe'llseelateron.

Serversiderendering

109

Page 110: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ContextAPITheContextAPIisaneatwaytopassstateacrosstheappwithouthavingtouseprops

TheContextAPIwasintroducedtoallowyoutopassstate(andenablethestatetoupdate)acrosstheapp,withouthavingtousepropsforit.

TheReactteamsuggeststosticktopropsifyouhavejustafewlevelsofchildrentopass,becauseit'sstillamuchlesscomplicatedAPIthantheContextAPI.

Inmanycases,itenablesustoavoidusingRedux,simplifyingourappsalot,andalsolearninghowtouseReact.

Howdoesitwork?

Youcreateacontextusing React.createContext(),whichreturnsaContextobject.:

const{Provider,Consumer}=React.createContext()

ThenyoucreateawrappercomponentthatreturnsaProvidercomponent,andyouaddaschildrenallthecomponentsfromwhichyouwanttoaccessthecontext:

classContainerextendsReact.Component{

constructor(props){

super(props)

this.state={

something:'hey'

}

}

render(){

return(

<Providervalue={{state:this.state}}>{this.props.children}</Provider>

)

}

}

classHelloWorldextendsReact.Component{

render(){

return(

<Container>

<Button/>

</Container>

)

}

}

ContextAPI

110

Page 111: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

IusedContainerasthenameofthiscomponentbecausethiswillbeaglobalprovider.Youcanalsocreatesmallercontexts.

Insideacomponentthat'swrappedinaProvider,youuseaConsumercomponenttomakeuseofthecontext:

classButtonextendsReact.Component{

render(){

return(

<Consumer>

{context=><button>{context.state.something}</button>}

</Consumer>

)

}

}

YoucanalsopassfunctionsintoaProvidervalue,andthosefunctionswillbeusedbytheConsumertoupdatethecontextstate:

<Providervalue={{

state:this.state,

updateSomething:()=>this.setState({something:'ho!'})

{this.props.children}

</Provider>

/*...*/

<Consumer>

{(context)=>(

<buttononClick={context.updateSomething}>{context.state.something}</button>

)}

</Consumer>

YoucanseethisinactioninthisGlitch.

Youcancreatemultiplecontexts,tomakeyourstatedistributedacrosscomponents,yetexposeitandmakeitreachablebyanycomponentyouwant.

Whenusingmultiplefiles,youcreatethecontentinonefile,andimportitinalltheplacesyouuseit:

//context.js

importReactfrom'react'

exportdefaultReact.createContext()

//component1.js

importContextfrom'./context'

//...useContext.Provider

//component2.js

importContextfrom'./context'

ContextAPI

111

Page 112: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

//...useContext.Consumer

ContextAPI

112

Page 113: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Higher-ordercomponentsFindoutwhatHigherOrderComponentsareandhowtheyareusefulwhenprogrammingaReactapplication

YoumightbefamiliarwithHigherOrderFunctionsinJavaScript.Thosearefunctionsthatacceptfunctionsasarguments,and/orreturnfunctions.

Twoexamplesofthosefunctionsare Array.map()or Array.filter().

InReact,weextendthisconcepttocomponents,andsowehaveaHigherOrderComponent(HOC)whenthecomponentacceptsacomponentasinputandreturnsacomponentasitsoutput.

Ingeneral,higherordercomponentsallowyoutocreatecodethat'scomposableandreusable,andalsomoreencapsulated.

WecanuseaHOCtoaddmethodsorpropertiestothestateofacomponent,oraReduxstoreforexample.

YoumightwanttouseHigherOrderComponentswhenyouwanttoenhanceanexistingcomponent,operateonthestateorprops,oritsrenderedmarkup.

ThereisaconventionofprependingaHigherOrderComponentwiththe withstring(it'saconvention,soit'snotmandatory),soifyouhavea Buttoncomponent,itsHOCcounterpartshouldbecalled withButton.

Let'screateone.

ThesimplestexampleeverofaHOCisonethatsimplyreturnsthecomponentunaltered:

constwithButton=Button=>()=><Button/>

Let'smakethisalittlebitmoreusefulandaddapropertytothatbutton,inadditiontoallthepropsitalreadycamewith,thecolor:

constwithButton=Element=>props=><Button{...props}color="red"/>

WeusethisHOCinacomponentJSX:

constButton=()=>{

return<button>test</button>

}

constWrappedButton=withButton(Button)

Higher-ordercomponents

113

Page 114: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

andwecanfinallyrendertheWrappedButtoncomponentinourappJSX:

functionApp(){

return(

<divclassName="App">

<h1>Hello</h1>

<WrappedButton/>

</div>

)

}

ThisisaverysimpleexamplebuthopefullyyoucangetthegistofHOCsbeforeapplyingthoseconceptstomorecomplexscenarios.

Higher-ordercomponents

114

Page 115: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

RenderPropsLearnhowRenderPropscanhelpyoubuildaReactapplication

Acommonpatternusedtosharestatebetweencomponentsistousethe childrenprop.

InsideacomponentJSXyoucanrender {this.props.children}whichautomaticallyinjectsanyJSXpassedintheparentcomponentasachildren:

classParentextendsReact.Component{

constructor(props){

super(props)

this.state={

/*...*/

}

}

render(){

return<div>{this.props.children}</div>

}

}

constChildren1=()=>{}

constChildren2=()=>{}

constApp=()=>(

<Parent>

<Children1/>

<Children2/>

</Parent>

)

However,thereisaproblemhere:thestateoftheparentcomponentcannotbeaccessedfromthechildren.

Tobeabletosharethestate,youneedtousearenderpropcomponent,andinsteadofpassingcomponentsaschildrenoftheparentcomponent,youpassafunctionwhichyouthenexecutein {this.props.children()}.Thefunctioncanacceptarguments,:

classParentextendsReact.Component{

constructor(props){

super(props)

this.state={name:'Flavio'}

}

render(){

return<div>{this.props.children(this.state.name)}</div>

}

}

RenderProps

115

Page 116: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

constChildren1=props=>{

return<p>{props.name}</p>

}

constApp=()=><Parent>{name=><Children1name={name}/>}</Parent>

Insteadofusingthe childrenprop,whichhasaveryspecificmeaning,youcanuseanyprop,andsoyoucanusethispatternmultipletimesonthesamecomponent:

classParentextendsReact.Component{

constructor(props){

super(props)

this.state={name:'Flavio',age:35}

}

render(){

return(

<div>

<p>Test</p>

{this.props.someprop1(this.state.name)}

{this.props.someprop2(this.state.age)}

</div>

)

}

}

constChildren1=props=>{

return<p>{props.name}</p>

}

constChildren2=props=>{

return<p>{props.age}</p>

}

constApp=()=>(

<Parent

someprop1={name=><Children1name={name}/>}

someprop2={age=><Children2age={age}/>}

/>

)

ReactDOM.render(<App/>,document.getElementById('app'))

RenderProps

116

Page 117: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

HooksLearnhowHookscanhelpyoubuildaReactapplication

HooksisafeaturethatwillbeintroducedinReact16.7,andisgoingtochangehowwewriteReactappsinthefuture.

BeforeHooksappeared,somekeythingsincomponentswereonlypossibleusingclasscomponents:havingtheirownstate,andusinglifecycleevents.Functioncomponents,lighterandmoreflexible,werelimitedinfunctionality.

Hooksallowfunctioncomponentstohavestateandtorespondtolifecycleeventstoo,andkindofmakeclasscomponentsobsolete.Theyalsoallowfunctioncomponentstohaveagoodwaytohandleevents.

AccessstateUsingthe useState()API,youcancreateanewstatevariable,andhaveawaytoalterit.useState()acceptstheinitialvalueofthestateitemandreturnsanarraycontainingthestatevariable,andthefunctionyoucalltoalterthestate.Sinceitreturnsanarrayweusearraydestructuringtoaccesseachindividualitem,likethis: const[count,setCount]=useState(0)

Here'sapracticalexample:

import{useState}from'react'

constCounter=()=>{

const[count,setCount]=useState(0)

return(

<div>

<p>Youclicked{count}times</p>

<buttononClick={()=>setCount(count+1)}>Clickme</button>

</div>

)

}

ReactDOM.render(<Counter/>,document.getElementById('app'))

Youcanaddasmany useState()callsyouwant,tocreateasmanystatevariablesasyouwant.Justmakesureyoucallitinthetoplevelofacomponent(notinan iforinanyotherblock).

ExampleonCodepen:

Hooks

117

Page 118: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

SeethePenReactHooksexample#1counterbyFlavioCopes(@flaviocopes)onCodePen.

AccesslifecyclehooksAnotherveryimportantfeatureofHooksisallowingfunctioncomponentstohaveaccesstothelifecyclehooks.

Usingclasscomponentsyoucanregisterafunctiononthe componentDidMount,componentWillUnmountand componentDidUpdateevents,andthosewillservemanyusecases,fromvariablesinitializationtoAPIcallstocleanup.

Hooksprovidethe useEffect()API.Thecallacceptsafunctionasargument.

Thefunctionrunswhenthecomponentisfirstrendered,andoneverysubsequentre-render/update.ReactfirstupdatestheDOM,thencallsanyfunctionpassedto useEffect().AllwithoutblockingtheUIrenderingevenonblockingcode,unliketheold componentDidMountand componentDidUpdate,whichmakesourappsfeelfaster.

Example:

const{useEffect,useState}=React

constCounterWithNameAndSideEffect=()=>{

const[count,setCount]=useState(0)

const[name,setName]=useState('Flavio')

useEffect(()=>{

console.log(`Hi${name}youclicked${count}times`)

})

return(

<div>

<p>

Hi{name}youclicked{count}times

</p>

<buttononClick={()=>setCount(count+1)}>Clickme</button>

<buttononClick={()=>setName(name==='Flavio'?'Roger':'Flavio')}>

Changename

</button>

</div>

)

}

ReactDOM.render(

<CounterWithNameAndSideEffect/>,

document.getElementById('app')

)

Hooks

118

Page 119: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thesame componentWillUnmountjobcanbeachievedbyoptionallyreturningafunctionfromour useEffect()parameter:

useEffect(()=>{

console.log(`Hi${name}youclicked${count}times`)

return()=>{

console.log(`Unmounted`)

}

})

useEffect()canbecalledmultipletimes,whichisnicetoseparateunrelatedlogic(somethingthatplaguestheclasscomponentlifecycleevents).

Sincethe useEffect()functionsarerunoneverysubsequentre-render/update,wecantellReacttoskiparun,forperformancepurposes,byaddingasecondparameterwhichisanarraythatcontainsalistofstatevariablestowatchfor.Reactwillonlyre-runthesideeffectifoneoftheitemsinthisarraychanges.

useEffect(

()=>{

console.log(`Hi${name}youclicked${count}times`)

},

[name,count]

)

SimilarlyyoucantellReacttoonlyexecutethesideeffectonce(atmounttime),bypassinganemptyarray:

useEffect(()=>{

console.log(`Componentmounted`)

},[])

useEffect()isgreatforaddinglogs,accessing3rdpartyAPIsandmuchmore.

ExampleonCodepen:

SeethePenReactHooksexample#3sideeffectsbyFlavioCopes(@flaviocopes)onCodePen.

HandleeventsinfunctioncomponentsBeforehooks,youeitherusedclasscomponents,oryoupassedaneventhandlerusingprops.

Nowwecanusethe useCallback()built-inAPI:

Hooks

119

Page 120: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

constButton=()=>{

consthandleClick=useCallback(()=>{

//...dosomething

})

return<buttononClick={handleClick}/>

}

AnyparameterusedinsidethefunctionmustbepassedthroughasecondparametertouseCallback(),inanarray:

constButton=()=>{

letname=''//...addlogic

consthandleClick=useCallback(

()=>{

//...dosomething

},

[name]

)

return<buttononClick={handleClick}/>

}

Enablecross-componentcommunicationusingcustomhooksTheabilitytowriteyourownhooksisthefeaturethatisgoingtosignificantlyalterhowyouwriteReactappsinthefuture.

Usingcustomhooksyouhaveonemorewaytosharestateandlogicbetweencomponents,addingasignificantimprovementtothepatternsofrenderpropsandhigherordercomponents.Whicharestillgreat,butnowwithcustomhookshavelessrelevanceinmanyusecases.

Howdoyoucreateacustomhook?

Ahookisjustafunctionthatconventionallystartswith use.Itcanacceptanarbitrarynumberofarguments,andreturnanythingitwants.

Examples:

constuseGetData(){

//...

returndata

}

or

Hooks

120

Page 121: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

constuseGetUser(username){

//...constuser=fetch(...)

//...constuserData=...

return[user,userData]

}

Inyourowncomponents,youcanusethehooklikethis:

constMyComponent=()=>{

constdata=useGetData()

const[user,userData]=useGetUser('flavio')

//...

}

Whenexactlytoaddhooksinsteadofregularfunctionsshouldbedeterminedonausecasebasis,andonlyexperiencewilltell.

Hooks

121

Page 122: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CodesplittingWhatisCodeSplittingandhowtointroduceitinaReactapp

ModernJavaScriptapplicationscanbequitehugeintermsofbundlesize.Youdon'twantyouruserstohavetodownloada1MBpackageofJavaScript(yourcodeandthelibrariesyouuse)justtoloadthefirstpage,right?ButthisiswhathappensbydefaultwhenyoushipamodernWebAppbuiltwithWebpackbundling.

Thatbundlewillcontaincodethatmightneverrunbecausetheuseronlystopsontheloginpageandneverseestherestofyourapp.

CodesplittingisthepracticeofonlyloadingtheJavaScriptyouneedthemomentwhenyouneedit.

Thisimproves:

theperformanceofyourapptheimpactonmemory,andsobatteryusageonmobiledevicesthedownloadedKiloBytes(orMegaBytes)size

React16.6.0,releasedinOctober2018,introducedawayofperformingcodesplittingthatshouldtaketheplaceofeverypreviouslyusedtoolorlibrary:React.lazyandSuspense.

React.lazyand Suspenseformtheperfectwaytolazilyloadadependencyandonlyloaditwhenneeded.

Let'sstartwith React.lazy.Youuseittoimportanycomponent:

importReactfrom'react'

constTodoList=React.lazy(()=>import('./TodoList'))

exportdefault()=>{

return(

<div>

<TodoList/>

</div>

)

}

theTodoListcomponentwillbedynamicallyaddedtotheoutputassoonasit'savailable.Webpackwillcreateaseparatebundleforit,andwilltakecareofloadingitwhennecessary.

Suspenseisacomponentthatyoucanusetowrapanylazilyloadedcomponent:

Codesplitting

122

Page 123: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

importReactfrom'react'

constTodoList=React.lazy(()=>import('./TodoList'))

exportdefault()=>{

return(

<div>

<React.Suspense>

<TodoList/>

</React.Suspense>

</div>

)

}

Ittakescareofhandlingtheoutputwhilethelazyloadedcomponentisfetchedandrendered.

Useits fallbackproptooutputsomeJSXoracomponentoutput:

...

<React.Suspensefallback={<p>Pleasewait</p>}>

<TodoList/>

</React.Suspense>

...

AllthisplayswellwithReactRouter:

importReactfrom'react'

import{BrowserRouterasRouter,Route,Switch}from'react-router-dom'

constTodoList=React.lazy(()=>import('./routes/TodoList'))

constNewTodo=React.lazy(()=>import('./routes/NewTodo'))

constApp=()=>(

<Router>

<React.Suspensefallback={<p>Pleasewait</p>}>

<Switch>

<Routeexactpath="/"component={TodoList}/>

<Routepath="/new"component={NewTodo}/>

</Switch>

</React.Suspense>

</Router>

)

Codesplitting

123

Page 124: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CSSinReactHowtouseCSStostyleaReactapplication

UsingReactyouhavevariouswaystoaddstylingtoyourcomponents.

UsingclassesandCSSThefirstandmostsimpleistouseclasses,anduseanormalCSSfiletotargetthoseclasses:

constButton=()=>{

return<buttonclassName="button">Abutton</button>

}

.button{

background-color:yellow;

}

Youcanimportthestylesheetusinganimportstatement,likethis:

import'./style.css'

andWebpackwilltakecareofaddingtheCSSpropertytothebundle.

UsingthestyleattributeAsecondmethodistousethe styleattributeattachedtoaJSXelement.Usingthisapproachyoudon'tneedaseparateCSSfile.

constButton=()=>{

return<buttonstyle={{backgroundColor:'yellow'}}>Abutton</button>

}

CSSisdefinedinaslightlydifferentwaynow.First,noticethedoublecurlybrackets:it'sbecause styleacceptsanobject.WepassinaJavaScriptobject,whichisdefinedincurlybraces.Wecouldalsodothis:

constbuttonStyle={backgroundColor:'yellow'}

constButton=()=>{

return<buttonstyle={buttonStyle}>Abutton</button>

CSSinReact

124

Page 125: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

}

Whenusing create-react-app,thosestylesareautoprefixedbydefaultthankstoitsuseofAutoprefixer.

Also,thestylenowiscamelCasedinsteadofusingdashes.EverytimeaCSSpropertyhasadash,removeitandstartthenextwordcapitalized.

Styleshavethebenefitofbeinglocaltothecomponent,andtheycannotleaktoothercomponentsinotherpartsoftheapp,somethingthatusingclassesandanexternalCSSfilecan'tprovide.

UsingCSSModulesCSSModulesseemtobeaperfectspotinthemiddle:youuseclasses,butCSSisscopedtothecomponent,whichmeansthatanystylingyouaddcannotbeappliedtoothercomponentswithoutyourpermission.AndyetyourstylesaredefinedinaseparateCSSfile,whichiseasiertomaintainthanCSSinJavaScript(andyoucanuseyourgoodoldCSSpropertynames).

StartbycreatingaCSSfilethatendswith .module.css,forexample Button.module.css.Agreatchoiceistogiveitthesamenameasthecomponentyouaregoingtostyle

AddyourCSShere,thenimportitinsidethecomponentfileyouwanttostyle:

importstylefrom'./Button.module.css'

nowyoucanuseitinyourJSX:

constButton=()=>{

return<buttonclassName={style.content}>Abutton</button>

}

That'sit!Intheresultingmarkup,Reactwillgenerateaspecific,uniqueclassforeachrenderedcomponent,andassigntheCSStothatclass,sothattheCSSisnotaffectingothermarkup.

CSSinReact

125

Page 126: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

CSSinReact

126

Page 127: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

SASSwithReactHowtouseSASStostyleaReactapplication

WhenyoubuildaReactapplicationusing create-react-app,youhavemanyoptionsatyourdisposalwhenitcomestostyling.

Ofcourse,ifnotusing create-react-app,youhaveallthechoicesintheworld,butwelimitthediscussiontothe create-react-app-providedoptions.

YoucanstyleusingplainclassesandCSSfiles,usingthestyleattributeorCSSModules,tostartwith.

SASS/SCSSisaverypopularoption,amuchlovedonebymanydevelopers.

Youcanuseitwithoutanyconfigurationatall,startingwith create-react-app2.

Allyouneedisa .sassor .scssfile,andyoujustimportitinacomponent:

import'./styles.scss'

Youcanseeanexampleofitworkingathttps://codesandbox.io/s/18qq31rp3.

SASSwithReact

127

Page 128: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

StyledComponentsStyledComponentsareoneofthenewwaystouseCSSinmodernJavaScript.ItisthemeanttobeasuccessorofCSSModules,awaytowriteCSSthat'sscopedtoasinglecomponent,andnotleaktoanyotherelementinthepage

AbriefhistoryOnceuponatime,theWebwasreallysimpleandCSSdidn'tevenexist.Welaidoutpagesusingtablesandframes.Goodtimes.

ThenCSScametolife,andaftersometimeitbecameclearthatframeworkscouldgreatlyhelpespeciallyinbuildinggridsandlayouts,BootstrapandFoundationplayingabigpartinthis.

PreprocessorslikeSASSandothershelpedalottoslowdowntheadoptionofframeworks,andtobetterorganizethecode,conventionslikeBEMandSMACSSgrewinuse,especiallywithinteams.

Conventionsarenotasolutiontoeverything,andtheyarecomplextoremember,sointhelastfewyearswiththeincreasingadoptionofJavaScriptandbuildprocessesineveryfrontendproject,CSSfounditswayintoJavaScript(CSS-in-JS).

NewtoolsexplorednewwaysofdoingCSS-in-JSandafewsucceededwithincreasingpopularity:

ReactStylejsxstyleRadium

andmore.

IntroducingStyledComponentsOneofthemostpopularofthesetoolsisStyledComponents.

ItisthemeanttobeasuccessortoCSSModules,awaytowriteCSSthat'sscopedtoasinglecomponent,andnotleaktoanyotherelementinthepage.

(moreonCSSmoduleshereandhere)

StyledComponents

128

Page 129: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

StyledComponentsallowyoutowriteplainCSSinyourcomponentswithoutworryingaboutclassnamecollisions.

InstallationSimplyinstallstyled-componentsusingnpmoryarn:

npminstallstyled-components

yarnaddstyled-components

That'sit!Nowallyouhavetodoistoaddthisimport:

importstyledfrom'styled-components'

YourfirststyledcomponentWiththe styledobjectimported,youcannowstartcreatingStyledComponents.Here'sthefirstone:

constButton=styled.button`

font-size:1.5em;

background-color:black;

color:white;

`

ButtonisnowaReactComponentinallitsgreatness.

Wecreateditusingafunctionofthestyledobject,called buttoninthiscase,andpassingsomeCSSpropertiesinatemplateliteral.

NowthiscomponentcanberenderedinourcontainerusingthenormalReactsyntax:

render(<Button/>)

StyledComponentsofferotherfunctionsyoucanusetocreateothercomponents,notjustbutton,like section, h1, inputandmanyothers.

Thesyntaxused,withthebacktick,mightbeweirdatfirst,butit'scalledTaggedTemplates,it'splainJavaScriptandit'sawaytopassanargumenttothefunction.

Usingpropstocustomizecomponents

StyledComponents

129

Page 130: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

WhenyoupasssomepropstoaStyledComponent,itwillpassthemdowntotheDOMnodemounted.

Forexamplehere'showwepassthe placeholderand typepropstoan inputcomponent:

constInput=styled.input`

//...

`

render(

<div>

<Inputplaceholder="..."type="text"/>

</div>

)

Thiswilldojustwhatyouthink,insertingthosepropsasHTMLattributes.

PropsinsteadofjustbeingblindlypasseddowntotheDOMcanalsobeusedtocustomizeacomponentbasedonthepropvalue.Here'sanexample:

constButton=styled.button`

background:${props=>(props.primary?'black':'white')};

color:${props=>(props.primary?'white':'black')};

`

render(

<div>

<Button>Anormalbutton</Button>

<Button>Anormalbutton</Button>

<Buttonprimary>Theprimarybutton</Button>

</div>

)

Settingthe primarypropchangesthecolorofthebutton.

ExtendinganexistingStyledComponentIfyouhaveonecomponentandyouwanttocreateasimilarone,juststyledslightlydifferently,youcanuse extend:

constButton=styled.button`

color:black;

//...

`

constWhiteButton=Button.extend`

color:white;

`

StyledComponents

130

Page 131: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

render(

<div>

<Button>Ablackbutton,likeallbuttons</Button>

<WhiteButton>Awhitebutton</WhiteButton>

</div>

)

It'sRegularCSSInStyledComponents,youcanusetheCSSyoualreadyknowandlove.It'sjustplainCSS.ItisnotpseudoCSSnorinlineCSSwithitslimitations.

Youcanusemediaqueries,nestingandanythingelseyoumightneed.

UsingVendorPrefixesStyledComponentsautomaticallyaddallthevendorprefixesneeded,soyoudon'tneedtoworryaboutthisproblem.

ConclusionThat'sitforthisStyledComponentsintroduction!TheseconceptswillhelpyougetanunderstandingoftheconceptandhelpyougetupandrunningwiththiswayofusingCSSinJavaScript.

StyledComponents

131

Page 132: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

BabelBabelisanawesomeentryintheWebDevelopertoolset.It'sanawesometool,andit’sbeenaroundforquitesometime,butnowadaysalmosteveryJavaScriptdeveloperreliesonit,andthiswillcontinuegoingon,becauseBabelisnowindispensableandhassolvedabigproblemforeveryone.

Babelisanawesometool,andit’sbeenaroundforquitesometime,butnowadaysalmosteveryJavaScriptdeveloperreliesonit,andthiswillcontinue,becauseBabelisnowindispensableandhassolvedabigproblemforeveryone.

Whichproblem?

TheproblemthateveryWebDeveloperhassurelyhad:afeatureofJavaScriptisavailableinthelatestreleaseofabrowser,butnotintheolderversions.OrmaybeChromeorFirefoximplementit,butSafariiOSandEdgedonot.

Forexample,ES6introducedthearrowfunction:

[1,2,3].map((n)=>n+1)

Whichisnowsupportedbyallmodernbrowsers.IE11doesnotsupportit,norOperaMini(HowdoIknow?BycheckingtheES6CompatibilityTable).

Sohowshouldyoudealwiththisproblem?Shouldyoumoveonandleavethosecustomerswitholder/incompatiblebrowsersbehind,orshouldyouwriteolderJavaScriptcodetomakeallyourusershappy?

EnterBabel.Babelisacompiler:ittakescodewritteninonestandard,andittranspilesittocodewrittenintoanotherstandard.

YoucanconfigureBabeltotranspilemodernES2017JavaScriptintoJavaScriptES5syntax:

[1,2,3].map(function(n){

returnn+1

})

Thismusthappenatbuildtime,soyoumustsetupaworkflowthathandlesthisforyou.Webpackisacommonsolution.

(P.S.ifallthisESthingsoundsconfusingtoyou,seemoreaboutESversionsintheECMAScriptguide)

Babel

132

Page 133: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

InstallingBabelBabeliseasilyinstalledusingnpm,locallyinaproject:

npminstall--save-dev@babel/core@babel/cli

InthepastIrecommendedinstalling babel-cliglobally,butthisisnowdiscouragedbytheBabelmaintainers,becausebyusingitlocallyyoucanhavedifferentversionsofBabelineachproject,andalsocheckinginbabelinyourrepositoryisbetterforteamwork

Sincenpmnowcomeswith npx,locallyinstalledCLIpackagescanrunbytypingthecommandintheprojectfolder:

SowecanrunBabelbyjustrunning

npxbabelscript.js

AnexampleBabelconfigurationBabeloutoftheboxdoesnotdoanythinguseful,youneedtoconfigureitandaddplugins.

HereisalistofBabelplugins

Tosolvetheproblemwetalkedaboutintheintroduction(usingarrowfunctionsineverybrowser),wecanrun

npminstall--save-dev\

@babel/plugin-transform-es2015-arrow-functions

todownloadthepackageinthe node_modulesfolderofourapp,thenweneedtoadd

{

"plugins":["transform-es2015-arrow-functions"]

}

tothe .babelrcfilepresentintheapplicationrootfolder.Ifyoudon'thavethatfilealready,youjustcreateablankfile,andputthatcontentintoit.

TIP:Ifyouhaveneverseenadotfile(afilestartingwithadot)itmightbeoddatfirstbecausethatfilemightnotappearinyourfilemanager,asit'sahiddenfile.

Nowifwehavea script.jsfilewiththiscontent:

Babel

133

Page 134: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

vara=()=>{};

vara=(b)=>b;

constdouble=[1,2,3].map((num)=>num*2);

console.log(double);//[2,4,6]

varbob={

_name:"Bob",

_friends:["Sally","Tom"],

printFriends(){

this._friends.forEach(f=>

console.log(this._name+"knows"+f));

}

};

console.log(bob.printFriends());

running babelscript.jswilloutputthefollowingcode:

vara=function(){};vara=function(b){

returnb;

};

constdouble=[1,2,3].map(function(num){

returnnum*2;

});console.log(double);//[2,4,6]

varbob={

_name:"Bob",

_friends:["Sally","Tom"],

printFriends(){

var_this=this;

this._friends.forEach(function(f){

returnconsole.log(_this._name+"knows"+f);

});

}

};

console.log(bob.printFriends());

AsyoucanseearrowfunctionshaveallbeenconvertedtoJavaScriptES5functions.

BabelpresetsWejustsawinthepreviousarticlehowBabelcanbeconfiguredtotranspilespecificJavaScriptfeatures.

Youcanaddmuchmoreplugins,butyoucan'taddtotheconfigurationfeaturesonebyone,it'snotpractical.

Babel

134

Page 135: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ThisiswhyBabelofferspresets.

Themostpopularpresetsare envand react.

Tip:Babel7deprecated(andremoved)yearlypresetslike preset-es2017,andstagepresets.Use @babel/preset-envinstead.

envpreset

The envpresetisverynice:youtellitwhichenvironmentsyouwanttosupport,anditdoeseverythingforyou,supportingallmodernJavaScriptfeatures.

E.g."supportthelast2versionsofeverybrowser,butforSafarilet'ssupportallversionssinceSafari7`

{

"presets":[

["env",{

"targets":{

"browsers":["last2versions","safari>=7"]

}

}]

]

}

or"Idon'tneedbrowsersupport,justletmeworkwithNode.js6.10"

{

"presets":[

["env",{

"targets":{

"node":"6.10"

}

}]

]

}

reactpreset

The reactpresetisveryconvenientwhenwritingReactapps:adding preset-flow, syntax-jsx, transform-react-jsx, transform-react-display-name.

Byincludingit,youareallreadytogodevelopingReactapps,withJSXtransformsandFlowsupport.

Moreinfoonpresets

Babel

135

Page 136: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

https://babeljs.io/docs/plugins/

UsingBabelwithwebpackIfyouwanttorunmodernJavaScriptinthebrowser,Babelonitsownisnotenough,youalsoneedtobundlethecode.Webpackistheperfecttoolforthis.

TIP:readthewebpackguideifyou'renotfamiliarwithwebpack

ModernJSneedstwodifferentstages:acompilestage,andaruntimestage.ThisisbecausesomeES6+featuresneedapolyfilloraruntimehelper.

ToinstalltheBabelpolyfillruntimefunctionality,run

npminstall@babel/polyfill\

@babel/runtime\

@babel/plugin-transform-runtime

Nowinyour webpack.config.jsfileadd:

entry:[

'babel-polyfill',

//yourappscriptsshouldbehere

],

module:{

loaders:[

//BabelloadercompilesES2015intoES5for

//completecross-browsersupport

{

loader:'babel-loader',

test:/\.js$/,

//onlyincludefilespresentinthe`src`subdirectory

include:[path.resolve(__dirname,"src")],

//excludenode_modules,equivalenttotheaboveline

exclude:/node_modules/,

query:{

//UsethedefaultES2015preset

//toincludeallES2015features

presets:['es2015'],

plugins:['transform-runtime']

}

}

]

}

Bykeepingthepresetsandpluginsinformationinsidethe webpack.config.jsfile,wecanavoidhavinga .babelrcfile.

Babel

136

Page 137: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Babel

137

Page 138: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

WebpackWebpackisatoolthathasgotalotofattentioninthelastfewyears,anditisnowseenusedinalmosteveryproject.Learnaboutit.

Whatiswebpack?WebpackisatoolthatletsyoucompileJavaScriptmodules,alsoknownasmodulebundler.

Givenalargenumberoffiles,itgeneratesasinglefile(orafewfiles)thatrunyourapp.

Itcanperformmanyoperations:

helpsyoubundleyourresources.watchesforchangesandre-runsthetasks.canrunBabeltranspilationtoES5,allowingyoutousethelatestJavaScriptfeatureswithoutworryingaboutbrowsersupport.cantranspileCoffeeScripttoJavaScriptcanconvertinlineimagestodataURIs.allowsyoutouserequire()forCSSfiles.

Webpack

138

Page 139: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

canrunadevelopmentwebserver.canhandlehotmodulereplacement.cansplittheoutputfilesintomultiplefiles,toavoidhavingahugejsfiletoloadinthefirstpagehit.canperformtreeshaking.

Webpackisnotlimitedtobeuseonthefrontend,it'salsousefulinbackendNode.jsdevelopmentaswell.

Predecessorsofwebpack,andstillwidelyusedtools,include:

GruntBroccoliGulp

TherearelotsofsimilaritiesinwhatthoseandWebpackcando,butthemaindifferenceisthatthoseareknownastaskrunners,whilewebpackwasbornasamodulebundler.

It'samorefocusedtool:youspecifyanentrypointtoyourapp(itcouldevenbeanHTMLfilewithscripttags)andwebpackanalyzesthefilesandbundlesallyouneedtoruntheappinasingleJavaScriptoutputfile(orinmorefilesifyouusecodesplitting).

InstallingwebpackWebpackcanbeinstalledgloballyorlocallyforeachproject.

Globalinstall

Here'showtoinstallitgloballywithYarn:

yarnglobaladdwebpackwebpack-cli

withnpm:

npmi-gwebpackwebpack-cli

oncethisisdone,youshouldbeabletorun

webpack-cli

Webpack

139

Page 140: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Localinstall

Webpackcanbeinstalledlocallyaswell.It'stherecommendedsetup,becausewebpackcanbeupdatedper-project,andyouhavelessresistancetousingthelatestfeaturesjustforasmallprojectratherthanupdatingalltheprojectsyouhavethatusewebpack.

WithYarn:

yarnaddwebpackwebpack-cli-D

withnpm:

npmiwebpackwebpack-cli--save-dev

Oncethisisdone,addthistoyour package.jsonfile:

{

//...

"scripts":{

"build":"webpack"

}

}

oncethisisdone,youcanrunwebpackbytyping

Webpack

140

Page 141: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

yarnbuild

intheprojectroot.

WebpackconfigurationBydefault,webpack(startingfromversion4)doesnotrequireanyconfigifyourespecttheseconventions:

theentrypointofyourappis ./src/index.jstheoutputisputin ./dist/main.js.Webpackworksinproductionmode

Youcancustomizeeverylittlebitofwebpackofcourse,whenyouneed.Thewebpackconfigurationisstoredinthe webpack.config.jsfile,intheprojectrootfolder.

TheentrypointBydefaulttheentrypointis ./src/index.jsThissimpleexampleusesthe ./index.jsfileasastartingpoint:

module.exports={

/*...*/

entry:'./index.js'

/*...*/

}

TheoutputBydefaulttheoutputisgeneratedin ./dist/main.js.Thisexampleputstheoutputbundleinto app.js:

module.exports={

/*...*/

output:{

path:path.resolve(__dirname,'dist'),

filename:'app.js'

}

/*...*/

}

Webpack

141

Page 142: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

LoadersUsingwebpackallowsyoutouse importor requirestatementsinyourJavaScriptcodetonotjustincludeotherJavaScript,butanykindoffile,forexampleCSS.

Webpackaimstohandleallourdependencies,notjustJavaScript,andloadersareonewaytodothat.

Forexample,inyourcodeyoucanuse:

import'style.css'

byusingthisloaderconfiguration:

module.exports={

/*...*/

module:{

rules:[

{test:/\.css$/,use:'css-loader'},

}]

}

/*...*/

}

TheregularexpressiontargetsanyCSSfile.

Aloadercanhaveoptions:

module.exports={

/*...*/

module:{

rules:[

{

test:/\.css$/,

use:[

{

loader:'css-loader',

options:{

modules:true

}

}

]

}

]

}

/*...*/

}

Youcanrequiremultipleloadersforeachrule:

Webpack

142

Page 143: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

module.exports={

/*...*/

module:{

rules:[

{

test:/\.css$/,

use:

[

'style-loader',

'css-loader',

]

}

]

}

/*...*/

}

Inthisexample, css-loaderinterpretsthe import'style.css'directiveintheCSS. style-loaderisthenresponsibleforinjectingthatCSSintheDOM,usinga <style>tag.

Theordermatters,andit'sreversed(thelastisexecutedfirst).

Whatkindofloadersarethere?Many!Youcanfindthefulllisthere.

AcommonlyusedloaderisBabel,whichisusedtotranspilemodernJavaScripttoES5code:

module.exports={

/*...*/

module:{

rules:[

{

test:/\.js$/,

exclude:/(node_modules|bower_components)/,

use:{

loader:'babel-loader',

options:{

presets:['@babel/preset-env']

}

}

}

]

}

/*...*/

}

ThisexamplemakesBabelpreprocessallourReact/JSXfiles:

module.exports={

/*...*/

module:{

rules:[

{

Webpack

143

Page 144: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

test:/\.(js|jsx)$/,

exclude:/node_modules/,

use:'babel-loader'

}

]

},

resolve:{

extensions:[

'.js',

'.jsx'

]

}

/*...*/

}

Seethe babel-loaderoptionshere.

PluginsPluginsarelikeloaders,butonsteroids.Theycandothingsthatloaderscan'tdo,andtheyarethemainbuildingblockofwebpack.

Takethisexample:

module.exports={

/*...*/

plugins:[

newHTMLWebpackPlugin()

]

/*...*/

}

The HTMLWebpackPluginpluginhasthejobofautomaticallycreatinganHTMLfile,addingtheoutputJSbundlepath,sotheJavaScriptisreadytobeserved.

Therearelotsofpluginsavailable.

Oneusefulplugin, CleanWebpackPlugin,canbeusedtoclearthe dist/folderbeforecreatinganyoutput,soyoudon'tleavefilesaroundwhenyouchangethenameoftheoutputfile:

module.exports={

/*...*/

plugins:[

newCleanWebpackPlugin(['dist']),

]

/*...*/

}

Webpack

144

Page 145: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ThewebpackmodeThismode(introducedinwebpack4)setstheenvironmentonwhichwebpackworks.Itcanbesetto developmentor production(defaultstoproduction,soyouonlysetitwhenmovingtodevelopment)

module.exports={

entry:'./index.js',

mode:'development',

output:{

path:path.resolve(__dirname,'dist'),

filename:'app.js'

}

}

Developmentmode:

buildsveryfastislessoptimizedthanproductiondoesnotremovecommentsprovidesmoredetailederrormessagesandsuggestionsprovidesabetterdebuggingexperience

Productionmodeisslowertobuild,sinceitneedstogenerateamoreoptimizedbundle.TheresultingJavaScriptfileissmallerinsize,asitremovesmanythingsthatarenotneededinproduction.

Imadeasampleappthatjustprintsa console.logstatement.

Here'stheproductionbundle:

Webpack

145

Page 146: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Here'sthedevelopmentbundle:

Webpack

146

Page 147: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

RunningwebpackWebpackcanberunfromthecommandlinemanuallyifinstalledglobally,butgenerallyyouwriteascriptinsidethe package.jsonfile,whichisthenrunusing npmor yarn.

Forexamplethis package.jsonscriptsdefinitionweusedbefore:

"scripts":{

"build":"webpack"

}

allowsustorun webpackbyrunning

npmrunbuild

or

yarnrunbuild

Webpack

147

Page 148: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

orsimply

yarnbuild

WatchingchangesWebpackcanautomaticallyrebuildthebundlewhenachangeinyourapphappens,andkeeplisteningforthenextchange.

Justaddthisscript:

"scripts":{

"watch":"webpack--watch"

}

andrun

npmrunwatch

or

yarnrunwatch

orsimply

yarnwatch

Onenicefeatureofthewatchmodeisthatthebundleisonlychangedifthebuildhasnoerrors.Ifthereareerrors, watchwillkeeplisteningforchanges,andtrytorebuildthebundle,butthecurrent,workingbundleisnotaffectedbythoseproblematicbuilds.

HandlingimagesWebpackallowsustouseimagesinaveryconvenientway,usingthe file-loaderloader.

Thissimpleconfiguration:

module.exports={

/*...*/

module:{

rules:[

Webpack

148

Page 149: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

{

test:/\.(png|svg|jpg|gif)$/,

use:[

'file-loader'

]

}

]

}

/*...*/

}

AllowsyoutoimportimagesinyourJavaScript:

importIconfrom'./icon.png'

constimg=newImage()

img.src=Icon

element.appendChild(img)

( imgisanHTMLImageElement.ChecktheImagedocs)

file-loadercanhandleotherassettypesaswell,likefonts,CSVfiles,xml,andmore.

Anothernicetooltoworkwithimagesisthe url-loaderloader.

ThisexampleloadsanyPNGfilesmallerthan8KBasadataURL.

module.exports={

/*...*/

module:{

rules:[

{

test:/\.png$/,

use:[

{

loader:'url-loader',

options:{

limit:8192

}

}

]

}

]

}

/*...*/

}

ProcessyourSASScodeandtransformittoCSS

Webpack

149

Page 150: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Using sass-loader, css-loaderand style-loader:

module.exports={

/*...*/

module:{

rules:[

{

test:/\.scss$/,

use:[

'style-loader',

'css-loader',

'sass-loader'

]

}

]

}

/*...*/

}

GenerateSourceMapsSincewebpackbundlesthecode,SourceMapsaremandatorytogetareferencetotheoriginalfilethatraisedanerror,forexample.

Youtellwebpacktogeneratesourcemapsusingthe devtoolpropertyoftheconfiguration:

module.exports={

/*...*/

devtool:'inline-source-map',

/*...*/

}

devtoolhasmanypossiblevalues,themostusedprobablyare:

none:addsnosourcemapssource-map:idealforproduction,providesaseparatesourcemapthatcanbeminimized,andaddsareferenceintothebundle,sodevelopmenttoolsknowthatthesourcemapisavailable.Ofcourseyoushouldconfiguretheservertoavoidshippingthis,andjustuseitfordebuggingpurposesinline-source-map:idealfordevelopment,inlinesthesourcemapasaDataURL

Webpack

150

Page 151: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

PrettierPrettierisanopinionatedcodeformatter.Itisagreatwaytokeepcodeformattedconsistentlyforyouandyourteam,andsupportsalotofdifferentlanguagesoutofthebox

Prettierisanopinionatedcodeformatter.

Itsupportsalotofdifferentsyntaxoutofthebox,including:

JavaScript

Prettier

151

Page 152: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Flow,TypeScriptCSS,SCSS,LessJSXGraphQLJSONMarkdown

andwithpluginsyoucanuseitforPython,PHP,Swift,Ruby,Javaandmore.

Itintegrateswiththemostpopularcodeeditors,includingVSCode,SublimeText,Atomandmore.

Prettierishugelypopular,asinFebruary2018ithasbeendownloadedover3.5milliontimes.

ThemostimportantlinksyouneedtoknowmoreaboutPrettierare

https://prettier.io/https://github.com/prettier/prettierhttps://www.npmjs.com/package/prettier

LessoptionsIlearnedGorecentlyandoneofthebestthingsaboutGoisgofmt,anofficialtoolthatautomaticallyformatsyourcodeaccordingtocommonstandards.

95%(madeupstat)oftheGocodearoundlooksexactlythesame,becausethistoolcanbeeasilyenforcedandsincethestyleisdefinedforyoubytheGomaintainers,youaremuchmorelikelytoadapttothatstandardinsteadofinsistingonyourownstyle.Liketabsvsspaces,orwheretoputanopeningbracket.

Thismightsoundlikealimitation,butit'sactuallyverypowerful.AllGocodelooksthesame.

Prettieristhe gofmtfortherestoftheworld.

Ithasveryfewoptions,andmostofthedecisionsarealreadytakenforyousoyoucanstoparguingaboutstyleandlittlethings,andfocusonyourcode.

DifferencewithESLintESLintisalinter,itdoesnotjustformat,butitalsohighlightssomeerrorsthankstoitsstaticanalysisofthecode.

ItisaninvaluabletoolanditcanbeusedalongsidePrettier.

Prettier

152

Page 153: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ESLintalsohighlightsformattingissues,butsinceit'salotmoreconfigurable,everyonecouldhaveadifferentsetofformattingrules.Prettierprovidesacommongroundforall.

Now,thereareafewthingsyoucancustomize,like:

thetabwidththeuseofsinglequotesvsdoublequotesthelinecolumnsnumbertheuseoftrailingcommas

andsomeothers,butPrettiertriestokeepthenumberofthosecustomizationsundercontrol,toavoidbecomingtoocustomizable.

InstallationPrettiercanrunfromthecommandline,andyoucaninstallitusingYarnornpm.

AnothergreatusecaseforPrettieristorunitonPRsforyourGitrepositories,forexampleonGitHub.

IfyouuseasupportededitorthebestthingistousePrettierdirectlyfromtheeditor,andthePrettierformattingwillberuneverytimeyousave.

ForexamplehereisthePrettierextensionforVSCode:https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

PrettierforbeginnersIfyouthinkPrettierisjustforteams,orforprousers,youaremissingagoodvaluepropositionofthistool.

Agoodstyleenforcesgoodhabits.

Formattingisatopicthat'smostlyoverlookedbybeginners,buthavingcleanandconsistentformattingiskeytoyoursuccessasanewdeveloper.

Also,evenifyoustartedusingJavaScript2weeksago,withPrettieryourcode-stylewise-willlookjustlikecodewrittenfromaJavaScriptGuruwritingJSsince1998.

Prettier

153

Page 154: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

IntroductiontoJestJestisalibraryfortestingJavaScriptcode.It'sanopensourceprojectmaintainedbyFacebook,andit'sespeciallywellsuitedforReactcodetesting,althoughnotlimitedtothat:itcantestanyJavaScriptcode.Jestisveryfastandeasytouse

JestisalibraryfortestingJavaScriptcode.

It'sanopensourceprojectmaintainedbyFacebook,andit'sespeciallywellsuitedforReactcodetesting,althoughnotlimitedtothat:itcantestanyJavaScriptcode.Itsstrengthsare:

it'sfastitcanperformsnapshottestingit'sopinionated,andprovideseverythingoutoftheboxwithoutrequiringyoutomakechoices

JestisatoolverysimilartoMocha,althoughtheyhavedifferences:

Mochaislessopinionated,whileJesthasacertainsetofconventionsMocharequiresmoreconfiguration,whileJestworksusuallyoutofthebox,thankstobeingopinionated

IntroductiontoJest

154

Page 155: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Mochaisolderandmoreestablished,withmoretoolingintegrations

InmyopinionthebiggestfeatureofJestisit'sanoutoftheboxsolutionthatworkswithouthavingtointeractwithothertestinglibrariestoperformitsjob.

InstallationJestisautomaticallyinstalledin create-react-app,soifyouusethat,youdon'tneedtoinstallJest.

JestcanbeinstalledinanyotherprojectusingYarn:

yarnadd--devjest

ornpm:

npminstall--save-devjest

noticehowweinstructbothtoputJestinthe devDependenciespartofthe package.jsonfile,sothatitwillonlybeinstalledinthedevelopmentenvironmentandnotinproduction.

Addthislinetothescriptspartofyour package.jsonfile:

{

"scripts":{

"test":"jest"

}

}

sothattestscanberunusing yarntestor npmruntest.

Alternatively,youcaninstallJestglobally:

yarnglobaladdjest

andrunallyourtestsusingthe jestcommandlinetool.

CreatethefirstJesttestProjectscreatedwith create-react-apphaveJestinstalledandpreconfiguredoutofthebox,butaddingJesttoanyprojectisaseasyastyping

IntroductiontoJest

155

Page 156: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

yarnadd--devjest

Addtoyour package.jsonthisline:

{

"scripts":{

"test":"jest"

}

}

andrunyourtestsbyexecuting yarntestinyourshell.

Now,youdon'thaveanytestshere,sonothingisgoingtobeexecuted:

Let'screatethefirsttest.Opena math.jsfileandtypeacouplefunctionsthatwe'lllatertest:

constsum=(a,b)=>a+b

constmul=(a,b)=>a*b

constsub=(a,b)=>a-b

constdiv=(a,b)=>a/b

exportdefault{sum,mul,sub,div}

Nowcreatea math.test.jsfile,inthesamefolder,andtherewe'lluseJesttotestthefunctionsdefinedin math.js:

const{sum,mul,sub,div}=require('./math')

test('Adding1+1equals2',()=>{

expect(sum(1,1)).toBe(2)

})

IntroductiontoJest

156

Page 157: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

test('Multiplying1*1equals1',()=>{

expect(mul(1,1)).toBe(1)

})

test('Subtracting1-1equals0',()=>{

expect(sub(1,1)).toBe(0)

})

test('Dividing1/1equals1',()=>{

expect(div(1,1)).toBe(1)

})

Running yarntestresultsinJestbeingrunonallthetestfilesitfinds,andreturningustheendresult:

RunJestwithVSCodeVisualStudioCodeisagreateditorforJavaScriptdevelopment.TheJestextensionoffersatopnotchintegrationforourtests.

Onceyouinstallit,itwillautomaticallydetectifyouhaveinstalledJestinyourdevDependenciesandrunthetests.YoucanalsoinvokethetestsmanuallybyselectingtheJest:StartRunnercommand.Itwillrunthetestsandstayinwatchmodetore-runthemwheneveryouchangeoneofthefilesthathaveatest(oratestfile):

IntroductiontoJest

157

Page 158: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

MatchersInthepreviousarticleIused toBe()astheonlymatcher:

test('Adding1+1equals2',()=>{

expect(sum(1,1)).toBe(2)

})

Amatcherisamethodthatletsyoutestvalues.

Mostcommonlyusedmatchers,comparingthevalueoftheresultof expect()withthevaluepassedinasargument,are:

toBecomparesstrictequality,using ===toEqualcomparesthevaluesoftwovariables.Ifit'sanobjectorarray,itcheckstheequalityofallthepropertiesorelementstoBeNullistruewhenpassinganullvaluetoBeDefinedistruewhenpassingadefinedvalue(oppositetotheabove)toBeUndefinedistruewhenpassinganundefinedvaluetoBeCloseToisusedtocomparefloatingvalues,avoidingroundingerrors

IntroductiontoJest

158

Page 159: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

toBeTruthytrueifthevalueisconsideredtrue(likean ifdoes)toBeFalsytrueifthevalueisconsideredfalse(likean ifdoes)toBeGreaterThantrueiftheresultofexpect()ishigherthantheargumenttoBeGreaterThanOrEqualtrueiftheresultofexpect()isequaltotheargument,orhigherthantheargumenttoBeLessThantrueiftheresultofexpect()islowerthantheargumenttoBeLessThanOrEqualtrueiftheresultofexpect()isequaltotheargument,orlowerthantheargumenttoMatchisusedtocomparestringswithregularexpressionpatternmatchingtoContainisusedinarrays,trueiftheexpectedarraycontainstheargumentinitselementssettoHaveLength(number):checksthelengthofanarraytoHaveProperty(key,value):checksifanobjecthasaproperty,andoptionallychecksitsvaluetoThrowchecksifafunctionyoupassthrowsanexception(ingeneral)oraspecificexceptiontoBeInstanceOf():checksifanobjectisaninstanceofaclass

Allthosematcherscanbenegatedusing .not.insidethestatement,forexample:

test('Adding1+1doesnotequal3',()=>{

expect(sum(1,1)).not.toBe(3)

})

Forusewithpromises,youcanuse .resolvesand .rejects:

expect(Promise.resolve('lemon')).resolves.toBe('lemon')

expect(Promise.reject(newError('octopus'))).rejects.toThrow('octopus')

SetupBeforerunningyourtestsyouwillwanttoperformsomeinitialization.

Todosomethingoncebeforeallthetestsrun,usethe beforeAll()function:

beforeAll(()=>{

//dosomething

})

Toperformsomethingbeforeeachtestruns,use beforeEach():

IntroductiontoJest

159

Page 160: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

beforeEach(()=>{

//dosomething

})

TeardownJustasyoucandowithsetup,youcanalsoperformsomethingaftereachtestruns:

afterEach(()=>{

//dosomething

})

andafteralltestsend:

afterAll(()=>{

//dosomething

})

Grouptestsusingdescribe()Youcancreategroupsoftests,inasinglefile,thatisolatethesetupandteardownfunctions:

describe('firstset',()=>{

beforeEach(()=>{

//dosomething

})

afterAll(()=>{

//dosomething

})

test(/*...*/)

test(/*...*/)

})

describe('secondset',()=>{

beforeEach(()=>{

//dosomething

})

beforeAll(()=>{

//dosomething

})

test(/*...*/)

test(/*...*/)

})

IntroductiontoJest

160

Page 161: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TestingasynchronouscodeAsynchronouscodeinmodernJavaScriptcanhavebasically2forms:callbacksandpromises.Ontopofpromiseswecanuseasync/await.

Callbacks

Youcan'thaveatestinacallback,becauseJestwon'texecuteit-theexecutionofthetestfileendsbeforethecallbackiscalled.Tofixthis,passaparametertothetestfunction,whichyoucanconvenientlycall done.Jestwillwaituntilyoucall done()beforeendingthattest:

//uppercase.js

functionuppercase(str,callback){

callback(str.toUpperCase())

}

module.exports=uppercase

//uppercase.test.js

constuppercase=require('./src/uppercase')

test(`uppercase'test'toequal'TEST'`,(done)=>{

uppercase('test',(str)=>{

expect(str).toBe('TEST')

done()

}

})

IntroductiontoJest

161

Page 162: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Promises

Withfunctionsthatreturnpromises,wesimplyreturnapromisefromthetest:

//uppercase.js

constuppercase=str=>{

returnnewPromise((resolve,reject)=>{

if(!str){

reject('Emptystring')

return

}

resolve(str.toUpperCase())

})

}

module.exports=uppercase

//uppercase.test.js

constuppercase=require('./uppercase')

test(`uppercase'test'toequal'TEST'`,()=>{

returnuppercase('test').then(str=>{

expect(str).toBe('TEST')

})

})

IntroductiontoJest

162

Page 163: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Promisesthatarerejectedcanbetestedusing .catch():

//uppercase.js

constuppercase=str=>{

returnnewPromise((resolve,reject)=>{

if(!str){

reject('Emptystring')

return

}

resolve(str.toUpperCase())

})

}

module.exports=uppercase

//uppercase.test.js

constuppercase=require('./uppercase')

IntroductiontoJest

163

Page 164: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

test(`uppercase'test'toequal'TEST'`,()=>{

returnuppercase('').catch(e=>{

expect(e).toMatch('Emptystring')

})

})

Async/await

Totestfunctionsthatreturnpromiseswecanalsouseasync/await,whichmakesthesyntaxverystraightforwardandsimple:

//uppercase.test.js

constuppercase=require('./uppercase')

IntroductiontoJest

164

Page 165: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

test(`uppercase'test'toequal'TEST'`,async()=>{

conststr=awaituppercase('test')

expect(str).toBe('TEST')

})

MockingIntesting,mockingallowsyoutotestfunctionalitythatdependson:

DatabaseNetworkrequestsaccesstoFilesanyExternalsystem

sothat:

1. yourtestsrunfaster,givingaquickturnaroundtimeduringdevelopment

IntroductiontoJest

165

Page 166: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

2. yourtestsareindependentofnetworkconditions,orthestateofthedatabase3. yourtestsdonotpolluteanydatastoragebecausetheydonottouchthedatabase4. anychangedoneinatestdoesnotchangethestateforsubsequenttests,andre-running

thetestsuiteshouldstartfromaknownandreproduciblestartingpoint5. youdon'thavetoworryaboutratelimitingonAPIcallsandnetworkrequests

Mockingisusefulwhenyouwanttoavoidsideeffects(e.g.writingtoadatabase)oryouwanttoskipslowportionsofcode(likenetworkaccess),andalsoavoidsimplicationswithrunningyourtestsmultipletimes(e.g.imagineafunctionthatsendsanemailorcallsarate-limitedAPI).

Evenmoreimportant,ifyouarewritingaUnitTest,youshouldtestthefunctionalityofafunctioninisolation,notwithallitsbaggageofthingsittouches.

Usingmocks,youcaninspectifamodulefunctionhasbeencalledandwhichparameterswereused,with:

expect().toHaveBeenCalled():checkifaspiedfunctionhasbeencalledexpect().toHaveBeenCalledTimes():counthowmanytimesaspiedfunctionhasbeencalledexpect().toHaveBeenCalledWith():checkifthefunctionhasbeencalledwithaspecificsetofparametersexpect().toHaveBeenLastCalledWith():checktheparametersofthelasttimethefunctionhasbeeninvoked

Spypackageswithoutaffectingthefunctionscode

Whenyouimportapackage,youcantellJestto"spy"ontheexecutionofaparticularfunction,using spyOn(),withoutaffectinghowthatmethodworks.

Example:

constmathjs=require('mathjs')

test(`Themathjslogfunction`,()=>{

constspy=jest.spyOn(mathjs,'log')

constresult=mathjs.log(10000,10)

expect(mathjs.log).toHaveBeenCalled()

expect(mathjs.log).toHaveBeenCalledWith(10000,10)

})

Mockanentirepackage

IntroductiontoJest

166

Page 167: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Jestprovidesaconvenientwaytomockanentirepackage.Createa __mocks__folderintheprojectroot,andinthisfoldercreateoneJavaScriptfileforeachofyourpackages.

Sayyouimport mathjs.Createa __mocks__/mathjs.jsfileinyourprojectroot,andaddthiscontent:

module.exports={

log:jest.fn(()=>'test')

}

Thiswillmockthelog()functionofthepackage.Addasmanyfunctionsasyouwanttomock:

constmathjs=require('mathjs')

test(`Themathjslogfunction`,()=>{

constresult=mathjs.log(10000,10)

expect(result).toBe('test')

expect(mathjs.log).toHaveBeenCalled()

expect(mathjs.log).toHaveBeenCalledWith(10000,10)

})

Mockasinglefunction

Moresimply,youcanmockasinglefunctionusing jest.fn():

constmathjs=require('mathjs')

mathjs.log=jest.fn(()=>'test')

test(`Themathjslogfunction`,()=>{

constresult=mathjs.log(10000,10)

expect(result).toBe('test')

expect(mathjs.log).toHaveBeenCalled()

expect(mathjs.log).toHaveBeenCalledWith(10000,10)

})

Youcanalsouse jest.fn().mockReturnValue('test')tocreateasimplemockthatdoesnothingexceptreturningavalue.

Pre-builtmocks

Youcanfindpre-mademocksforpopularlibraries.Forexamplethispackagehttps://github.com/jefflau/jest-fetch-mockallowsyoutomock fetch()calls,andprovidesamplereturnvalueswithoutinteractingwiththeactualserverinyourtests.

Snapshottesting

IntroductiontoJest

167

Page 168: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

SnapshottestingisaprettycoolfeatureofferedbyJest.ItcanmemorizehowyourUIcomponentsarerendered,andcompareittothecurrenttest,raisinganerrorifthere'samismatch.

ThisisasimpletestontheAppcomponentofasimple create-react-appapplication(makesureyouinstall react-test-renderer):

importReactfrom'react'

importAppfrom'./App'

importrendererfrom'react-test-renderer'

it('renderscorrectly',()=>{

consttree=renderer.create(<App/>).toJSON()

expect(tree).toMatchSnapshot()

})

thefirsttimeyourunthistest,Jestsavesthesnapshottothe __snapshots__folder.Here'swhatApp.test.js.snapcontains:

//JestSnapshotv1,https://goo.gl/fbAQLP

exports[`renderscorrectly1`]=`

<div

className="App"

>

<header

className="App-header"

>

<img

alt="logo"

className="App-logo"

src="logo.svg"

/>

<h1

className="App-title"

>

WelcometoReact

</h1>

</header>

<p

className="App-intro"

>

Togetstarted,edit

<code>

src/App.js

</code>

andsavetoreload.

</p>

</div>

`

IntroductiontoJest

168

Page 169: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Asyouseeit'sthecodethattheAppcomponentrenders,nothingmore.

Thenexttimethetestcomparestheoutputof <App/>tothis.IfAppchanges,yougetanerror:

Whenusing yarntestin create-react-appyouareinwatchmode,andfromthereyoucanpress wandshowmoreoptions:

WatchUsage

›Pressutoupdatefailingsnapshots.

›Pressptofilterbyafilenameregexpattern.

›Pressttofilterbyatestnameregexpattern.

›Pressqtoquitwatchmode.

›PressEntertotriggeratestrun.

IntroductiontoJest

169

Page 170: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Ifyourchangeisintended,pressing uwillupdatethefailingsnapshots,andmakethetestpass.

Youcanalsoupdatethesnapshotbyrunning jest-u(or jest--updateSnapshot)outsideofwatchmode.

IntroductiontoJest

170

Page 171: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

TestingReactComponentsTestyourfirstReactcomponentusingJestand`react-testing-library`

TheeasiestwaytostartwithtestingReactcomponentsisdoingsnapshottesting,atestingtechniquethatletsyoutestcomponentsinisolation.

Ifyouarefamiliarwithtestingsoftware,it'sjustlikeunittestingyoudoforclasses:youtesteachcomponentfunctionality.

IassumeyoucreatedaReactappwith create-react-app,whichalreadycomeswithJestinstalled,thetestingpackagewe'llneed.

Let'sstartwithasimpletest.CodeSandboxisagreatenvironmenttotrythisout.StartwithaReactsandbox,andcreatean App.jscomponentina componentsfolder,andaddanApp.test.jsfile.

importReactfrom'react'

exportdefaultfunctionApp(){

return(

<divclassName="App">

<h1>HelloCodeSandbox</h1>

<h2>Starteditingtoseesomemagichappen!</h2>

</div>

)

}

Ourfirsttestisdumb:

test('Firsttest',()=>{

expect(true).toBeTruthy()

})

WhenCodeSandboxdetectstestfiles,itautomaticallyrunsthemforyou,andyoucanclicktheTestsbuttoninthebottomoftheviewtoshowyourtestresults:

TestingReactComponents

171

Page 172: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Atestfilecancontainmultipletests:

Let'sdosomethingabitmoreusefulnow,toactuallytestaReactcomponent.WeonlyhaveAppnow,whichisnotdoinganythingreallyuseful,solet'sfirstsetuptheenvironmentwithalittleapplicationwithmorefunctionality:thecounterappwebuiltpreviously.Ifyouskippedit,youcangobackandreadhowwebuiltit,butforeasierreferenceIaddithereagain.

TestingReactComponents

172

Page 173: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

It'sjust2components:AppandButton.Createthe App.jsfile:

importReact,{useState}from'react'

importButtonfrom'./Button'

constApp=()=>{

const[count,setCount]=useState(0)

constincrementCount=increment=>{

setCount(count+increment)

}

return(

<div>

<Buttonincrement={1}onClickFunction={incrementCount}/>

<Buttonincrement={10}onClickFunction={incrementCount}/>

<Buttonincrement={100}onClickFunction={incrementCount}/>

<Buttonincrement={1000}onClickFunction={incrementCount}/>

<span>{count}</span>

</div>

)

}

exportdefaultApp

andthe Button.jsfile:

importReactfrom'react'

constButton=({increment,onClickFunction})=>{

consthandleClick=()=>{

onClickFunction(increment)

}

return<buttononClick={handleClick}>+{increment}</button>

}

exportdefaultButton

Wearegoingtousethe react-testing-library,whichisagreathelpasitallowsustoinspecttheoutputofeverycomponentandtoapplyeventsonthem.Youcanreadmoreaboutitonhttps://github.com/kentcdodds/react-testing-libraryorbywatchingthisvideo.

Let'stesttheButtoncomponentfirst.

Westartbyimporting renderand fireEventfrom react-testing-library,twohelpers.ThefirstletsusrenderJSX.Thesecondletsusemiteventsonacomponent.

Createa Button.test.jsandputitinthesamefolderas Button.js.

importReactfrom'react'

import{render,fireEvent}from'react-testing-library'

TestingReactComponents

173

Page 174: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

importButtonfrom'./Button'

ButtonsareusedintheapptoacceptaclickeventandthentheycallafunctionpassedtotheonClickFunctionprop.Weadda countvariableandwecreateafunctionthatincrementsit:

letcount

constincrementCount=increment=>{

count+=increment

}

Nowofftotheactualtests.Wefirstinitializecountto0,andwerendera +1 Buttoncomponentpassinga 1to incrementandour incrementCountfunctionto onClickFunction.

Thenwegetthecontentofthefirstchildofthecomponent,andwecheckitoutputs +1.

Wethenproceedtoclickingthebutton,andwecheckthatthecountgotfrom0to1:

test('+1Buttonworks',()=>{

count=0

const{container}=render(

<Buttonincrement={1}onClickFunction={incrementCount}/>

)

constbutton=container.firstChild

expect(button.textContent).toBe('+1')

expect(count).toBe(0)

fireEvent.click(button)

expect(count).toBe(1)

})

Similarlywetesta+100button,thistimecheckingtheoutputis +100andthebuttonclickincrementsthecountof100.

test('+100Buttonworks',()=>{

count=0

const{container}=render(

<Buttonincrement={100}onClickFunction={incrementCount}/>

)

constbutton=container.firstChild

expect(button.textContent).toBe('+100')

expect(count).toBe(0)

fireEvent.click(button)

expect(count).toBe(100)

})

Let'stesttheAppcomponentnow.Itshows4buttonsandtheresultinthepage.Wecaninspecteachbuttonandseeiftheresultincreaseswhenweclickthem,clickingmultipletimesaswell:

TestingReactComponents

174

Page 175: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

importReactfrom'react'

import{render,fireEvent}from'react-testing-library'

importAppfrom'./App'

test('Appworks',()=>{

const{container}=render(<App/>)

console.log(container)

constbuttons=container.querySelectorAll('button')

expect(buttons[0].textContent).toBe('+1')

expect(buttons[1].textContent).toBe('+10')

expect(buttons[2].textContent).toBe('+100')

expect(buttons[3].textContent).toBe('+1000')

constresult=container.querySelector('span')

expect(result.textContent).toBe('0')

fireEvent.click(buttons[0])

expect(result.textContent).toBe('1')

fireEvent.click(buttons[1])

expect(result.textContent).toBe('11')

fireEvent.click(buttons[2])

expect(result.textContent).toBe('111')

fireEvent.click(buttons[3])

expect(result.textContent).toBe('1111')

fireEvent.click(buttons[2])

expect(result.textContent).toBe('1211')

fireEvent.click(buttons[1])

expect(result.textContent).toBe('1221')

fireEvent.click(buttons[0])

expect(result.textContent).toBe('1222')

})

CheckthecodeworkingonthisCodeSandbox:https://codesandbox.io/s/pprl4y0wq

TestingReactComponents

175

Page 176: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ReactRouterReactRouter4istheperfecttooltolinktogethertheURLandyourReactapp.ReactRouteristhede-factoReactroutinglibrary,andit'soneofthemostpopularprojectsbuiltontopofReact.

ThistutorialintroducesReactRouter4,thelaststableversion

ReactRouteristhede-factoReactroutinglibrary,andit'soneofthemostpopularprojectsbuiltontopofReact.

Reactatitscoreisaverysimplelibrary,anditdoesnotdictateanythingaboutrouting.

RoutinginaSinglePageApplicationisthewaytointroducesomefeaturestonavigatingtheappthroughlinks,whichareexpectedinnormalwebapplications:

1. ThebrowsershouldchangetheURLwhenyounavigatetoadifferentscreen2. Deeplinkingshouldwork:ifyoupointthebrowsertoaURL,theapplicationshould

reconstructthesameviewthatwaspresentedwhentheURLwasgenerated.3. Thebrowserback(andforward)buttonshouldworklikeexpected.

Routinglinkstogetheryourapplicationnavigationwiththenavigationfeaturesofferedbythebrowser:theaddressbarandthenavigationbuttons.

ReactRouteroffersawaytowriteyourcodesothatitwillshowcertaincomponentsofyourapponlyiftheroutematcheswhatyoudefine.

Installation

ReactRouter

176

Page 177: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Withnpm:

npminstallreact-router-dom

WithYarn:

yarnaddreact-router-dom

TypesofroutesReactRouterprovidestwodifferentkindofroutes:

BrowserRouter

HashRouter

OnebuildsclassicURLs,theotherbuildsURLswiththehash:

https://application.com/dashboard/*BrowserRouter*/

https://application.com/#/dashboard/*HashRouter*/

Whichonetouseismainlydictatedbythebrowsersyouneedtosupport. BrowserRouterusestheHistoryAPI,whichisrelativelyrecent,andnotsupportedinIE9andbelow.Ifyoudon'thavetoworryaboutolderbrowsers,it'stherecommendedchoice.

ComponentsThe3componentsyouwillinteractthemostwhenworkingwithReactRouterare:

BrowserRouter,usuallyaliasedas RouterLink

Route

BrowserRouterwrapsallyourRoutecomponents.

Linkcomponentsare-asyoucanimagine-usedtogeneratelinkstoyourroutes

Routecomponentsareresponsibleforshowing-orhiding-thecomponentstheycontain.

BrowserRouter

ReactRouter

177

Page 178: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Here'sasimpleexampleoftheBrowserRoutercomponent.Youimportitfromreact-router-dom,andyouuseittowrapallyourapp:

importReactfrom'react'

importReactDOMfrom'react-dom'

import{BrowserRouterasRouter}from'react-router-dom'

ReactDOM.render(

<Router>

<div>

<!---->

</div>

</Router>,

document.getElementById('app')

)

ABrowserRoutercomponentcanonlyhaveonechildelement,sowewrapallwe'regoingtoaddina divelement.

LinkTheLinkcomponentisusedtotriggernewroutes.Youimportitfrom react-router-dom,andyoucanaddtheLinkcomponentstopointatdifferentroutes,withthe toattribute:

importReactfrom'react'

importReactDOMfrom'react-dom'

import{BrowserRouterasRouter,Link}from'react-router-dom'

ReactDOM.render(

<Router>

<div>

<aside>

<Linkto={`/dashboard`}>Dashboard</Link>

<Linkto={`/about`}>About</Link>

</aside>

<!---->

</div>

</Router>,

document.getElementById('app')

)

RouteNowlet'saddtheRoutecomponentintheabovesnippettomakethingsactuallyworkaswewant:

ReactRouter

178

Page 179: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

importReactfrom'react'

importReactDOMfrom'react-dom'

import{BrowserRouterasRouter,Link,Route}from'react-router-dom'

constDashboard=()=>(

<div>

<h2>Dashboard</h2>

...

</div>

)

constAbout=()=>(

<div>

<h2>About</h2>

...

</div>

)

ReactDOM.render(

<Router>

<div>

<aside>

<Linkto={`/`}>Dashboard</Link>

<Linkto={`/about`}>About</Link>

</aside>

<main>

<Routeexactpath="/"component={Dashboard}/>

<Routepath="/about"component={About}/>

</main>

</div>

</Router>,

document.getElementById('app')

)

CheckthisexampleonGlitch:https://flaviocopes-react-router-v4.glitch.me/

Whentheroutematches /,theapplicationshowstheDashboardcomponent.

Whentherouteischangedbyclickingthe"About"linkto /about,theDashboardcomponentisremovedandtheAboutcomponentisinsertedintheDOM.

Noticethe exactattribute.Withoutthis, path="/"wouldalsomatch /about,since /iscontainedintheroute.

MatchmultiplepathsYoucanhavearouterespondtomultiplepathssimplyusingaregex,because pathcanbearegularexpressionsstring:

ReactRouter

179

Page 180: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

<Routepath="/(about|who)/"component={Dashboard}/>

InlinerenderingInsteadofspecifyinga componentpropertyon Route,youcanseta renderprop:

<Route

path="/(about|who)/"

render={()=>(

<div>

<h2>About</h2>

...

</div>

)}

/>

MatchdynamicrouteparameterYoualreadysawhowtousestaticrouteslike

constPosts=()=>(

<div>

<h2>Posts</h2>

...

</div>

)

//...

<Routeexactpath="/posts"component={Posts}/>

Here'showtohandledynamicroutes:

constPost=({match})=>(

<div>

<h2>Post#{match.params.id}</h2>

...

</div>

)

//...

<Routeexactpath="/post/:id"component={Post}/>

InyourRoutecomponentyoucanlookupthedynamicparametersin match.params.

ReactRouter

180

Page 181: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

matchisalsoavailableininlinerenderedroutes,andthisisespeciallyusefulinthiscase,becausewecanusethe idparametertolookupthepostdatainourdatasourcebeforerenderingPost:

constposts=[

{id:1,title:'First',content:'Helloworld!'},

{id:2,title:'Second',content:'Helloagain!'}

]

constPost=({post})=>(

<div>

<h2>{post.title}</h2>

{post.content}

</div>

)

//...

<Routeexactpath="/post/:id"render={({match})=>(

<Postpost={posts.find(p=>p.id===match.params.id)}/>

)}/>

ReactRouter

181

Page 182: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

ReduxReduxisastatemanagerthat'susuallyusedalongwithReact,butit'snottiedtothatlibrary.LearnReduxbyreadingthissimpleandeasytofollowguide

WhyyouneedReduxReduxisastatemanagerthat'susuallyusedalongwithReact,butit'snottiedtothatlibrary-itcanbeusedwithothertechnologiesaswell,butwe'llsticktoReactforthesakeoftheexplanation.

Reacthasitsownwaytomanagestate,asyoucanreadontheReactBeginner'sGuide,whereIintroducehowyoucanmanageStateinReact.

Movingthestateupinthetreeworksinsimplecases,butinacomplexappyoumightfindyouaremovingalmostallthestateup,andthendownusingprops.

Reactinversion16.3.0introducedtheContextAPI,whichmakesReduxredundantfortheusecaseofaccessingthestatefromdifferentpartsofyourapp,soconsiderusingtheContextAPIinsteadofRedux,unlessyouneedaspecificfeaturethatReduxprovides.

Reduxisawaytomanageanapplicationstate,andmoveittoanexternalglobalstore.

Thereareafewconceptstograsp,butonceyoudo,Reduxisaverysimpleapproachtotheproblem.

ReduxisverypopularwithReactapplications,butit'sinnowayuniquetoReact:therearebindingsfornearlyanypopularframework.Thatsaid,I'llmakesomeexamplesusingReactasitisitsprimaryusecase.

WhenshouldyouuseRedux?Reduxisidealformediumtobigapps,andyoushouldonlyuseitwhenyouhavetroublemanagingthestatewiththedefaultstatemanagementofReact,ortheotherlibraryyouuse.

Simpleappsshouldnotneeditatall(andthere'snothingwrongwithsimpleapps).

ImmutableStateTree

Redux

182

Page 183: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

InRedux,thewholestateoftheapplicationisrepresentedbyoneJavaScriptobject,calledStateorStateTree.

WecallitImmutableStateTreebecauseitisreadonly:itcan'tbechangeddirectly.

ItcanonlybechangedbydispatchinganAction.

ActionsAnActionisaJavaScriptobjectthatdescribesachangeinaminimalway(withjusttheinformationneeded):

{

type:'CLICKED_SIDEBAR'

}

//e.g.withmoredata

{

type:'SELECTED_USER',

userId:232

}

Theonlyrequirementofanactionobjectishavinga typeproperty,whosevalueisusuallyastring.

Actionstypesshouldbeconstants

Inasimpleappanactiontypecanbedefinedasastring,asIdidintheexampleinthepreviouslesson.

Whentheappgrowsisbesttouseconstants:

constADD_ITEM='ADD_ITEM'

constaction={type:ADD_ITEM,title:'Thirditem'}

andtoseparateactionsintheirownfiles,andimportthem

import{ADD_ITEM,REMOVE_ITEM}from'./actions'

Actioncreators

ActionsCreatorsarefunctionsthatcreateactions.

functionaddItem(t){

Redux

183

Page 184: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

return{

type:ADD_ITEM,

title:t

}

}

Youusuallyrunactioncreatorsincombinationwithtriggeringthedispatcher:

dispatch(addItem('Milk'))

orbydefininganactiondispatcherfunction:

constdispatchAddItem=i=>dispatch(addItem(i))

dispatchAddItem('Milk')

ReducersWhenanactionisfired,somethingmusthappen,thestateoftheapplicationmustchange.

Thisisthejobofreducers.

Whatisareducer

AreducerisapurefunctionthatcalculatesthenextStateTreebasedonthepreviousStateTree,andtheactiondispatched.

;(currentState,action)=>newState

Apurefunctiontakesaninputandreturnsanoutputwithoutchangingtheinputoranythingelse.Thus,areducerreturnsacompletelynewstatetreeobjectthatsubstitutesthepreviousone.

Whatareducershouldnotdo

Areducershouldbeapurefunction,soitshould:

nevermutateitsargumentsnevermutatethestate,butinsteadcreateanewonewith Object.assign({},...)nevergenerateside-effects(noAPIcallschanginganything)nevercallnon-purefunctions,functionsthatchangetheiroutputbasedonfactorsotherthantheirinput(e.g. Date.now()or Math.random())

Redux

184

Page 185: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thereisnoreinforcement,butyoushouldsticktotherules.

Multiplereducers

Sincethestateofacomplexappcouldbereallywide,thereisnotasinglereducer,butmanyreducersforanykindofaction.

Asimulationofareducer

Atitscore,Reduxcanbesimplifiedwiththissimplemodel:

Thestate

{

list:[

{title:"Firstitem"},

{title:"Seconditem"},

],

title:'Grocerieslist'

}

Alistofactions

{type:'ADD_ITEM',title:'Thirditem'}

{type:'REMOVE_ITEM',index:1}

{type:'CHANGE_LIST_TITLE',title:'Roadtriplist'}

Areducerforeverypartofthestate

consttitle=(state='',action)=>{

if(action.type==='CHANGE_LIST_TITLE'){

returnaction.title

}else{

returnstate

}

}

constlist=(state=[],action)=>{

switch(action.type){

case'ADD_ITEM':

returnstate.concat([{title:action.title}])

case'REMOVE_ITEM':

returnstate.map((item,index)=>

action.index===index

?{title:item.title}

:item

Redux

185

Page 186: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

default:

returnstate

}

}

Areducerforthewholestate

constlistManager=(state={},action)=>{

return{

title:title(state.title,action),

list:list(state.list,action)

}

}

TheStoreTheStoreisanobjectthat:

holdsthestateoftheappexposesthestatevia getState()allowsustoupdatethestatevia dispatch()allowsusto(un)registerastatechangelistenerusing subscribe()

Astoreisuniqueintheapp.

HereishowastoreforthelistManagerappiscreated:

import{createStore}from'redux'

importlistManagerfrom'./reducers'

letstore=createStore(listManager)

CanIinitializethestorewithserver-sidedata?

Sure,justpassastartingstate:

letstore=createStore(listManager,preexistingState)

Gettingthestate

store.getState()

Updatethestate

Redux

186

Page 187: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

store.dispatch(addItem('Something'))

Listentostatechanges

constunsubscribe=store.subscribe(()=>

constnewState=store.getState()

)

unsubscribe()

DataFlowDataflowinReduxisalwaysunidirectional.

Youcall dispatch()ontheStore,passinganAction.

TheStoretakescareofpassingtheActiontotheReducer,generatingthenextState.

TheStoreupdatestheStateandalertsalltheListeners.

Redux

187

Page 188: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Next.jsNext.jsisaverypopularNode.jsframeworkwhichenableseasyserver-sideReactrendering,andprovidesmanyotheramazingfeatures

WorkingonamodernJavaScriptapplicationpoweredbyReactisawesomeuntilyourealizethatthereareacoupleproblemsrelatedtorenderingallthecontentontheclient-side.

First,thepagetakeslongertothebecomevisibletotheuser,becausebeforethecontentloads,alltheJavaScriptmustload,andyourapplicationneedstoruntodeterminewhattoshowonthepage.

Second,ifyouarebuildingapubliclyavailablewebsite,youhaveacontentSEOissue.SearchenginesaregettingbetteratrunningandindexingJavaScriptapps,butit'smuchbetterifwecansendthemcontentinsteadoflettingthemfigureitout.

Thesolutiontobothofthoseproblemsisserverrendering,alsocalledstaticpre-rendering.

Next.jsisoneReactframeworktodoallofthisinaverysimpleway,butit'snotlimitedtothis.It'sadvertisedbyitscreatorsasazero-configuration,single-commandtoolchainforReactapps.

ItprovidesacommonstructurethatallowsyoutoeasilybuildafrontendReactapplication,andtransparentlyhandleserver-siderenderingforyou.

Next.js

188

Page 189: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

MainfeaturesHereisanon-exhaustivelistofthemainNext.jsfeatures:

HotCodeReloading:Next.jsreloadsthepagewhenitdetectsanychangesavedtodisk.AutomaticRouting:anyURLismappedtothefilesystem,tofilesputinthe pagesfolder,andyoudon'tneedanyconfiguration(youhavecustomizationoptionsofcourse).SingleFileComponents:usingstyled-jsx,completelyintegratedasbuiltbythesameteam,it'strivialtoaddstylesscopedtothecomponent.ServerRendering:youcan(optionally)renderReactcomponentsontheserverside,beforesendingtheHTMLtotheclient.EcosystemCompatibility:Next.jsplayswellwiththerestoftheJavaScript,NodeandReactecosystem.AutomaticCodeSplitting:pagesarerenderedwithjustthelibrariesandJavaScriptthattheyneed,nomore.Prefetching:the Linkcomponent,usedtolinktogetherdifferentpages,supportsaprefetchpropwhichautomaticallyprefetchespageresources(includingcodemissingduetocodesplitting)inthebackground.DynamicComponents:youcanimportJavaScriptmodulesandReactComponentsdynamically(https://github.com/zeit/next.js#dynamic-import).StaticExports:usingthe nextexportcommand,Next.jsallowsyoutoexportafullystaticsitefromyourapp.

InstallationNext.jssupportsallthemajorplatforms:Linux,macOS,Windows.

ANext.jsprojectisstartedeasilywithnpm:

npminstallnextreactreact-dom

orwithYarn:

yarnaddnextreactreact-dom

GettingstartedCreatea package.jsonfilewiththiscontent:

Next.js

189

Page 190: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

{

"scripts":{

"dev":"next"

}

}

Ifyourunthiscommandnow:

npmrundev

thescriptwillraiseanerrorcomplainingaboutnotfindingthe pagesfolder.ThisistheonlythingthatNext.jsrequirestorun.

Createanempty pagesfolder,andrunthecommandagain,andNext.jswillstartupaserveron localhost:3000.

IfyougotothatURLnow,you'llbegreetedbyafriendly404page,withanicecleandesign.

Next.jshandlesothererrortypesaswell,like500errorsforexample.

CreateapageInthe pagesfoldercreatean index.jsfilewithasimpleReactfunctionalcomponent:

exportdefault()=>(

<div>

<p>HelloWorld!</p>

</div>

)

Ifyouvisit localhost:3000,thiscomponentwillautomaticallyberendered.

Next.js

190

Page 191: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Whyisthissosimple?

Next.jsusesadeclarativepagesstructure,whichisbasedonthefilesystemstructure.

Simplyput,pagesareinsidea pagesfolder,andthepageURLisdeterminedbythepagefilename.ThefilesystemisthepagesAPI.

Server-siderenderingOpenthepagesource, View->Developer->ViewSourcewithChrome.

Asyoucansee,theHTMLgeneratedbythecomponentissentdirectlyinthepagesource.It'snotrenderedclient-side,butinsteadit'srenderedontheserver.

TheNext.jsteamwantedtocreateadeveloperexperienceforserverrenderedpagessimilartotheoneyougetwhencreatingabasicPHPproject,whereyousimplydropPHPfilesandyoucallthem,andtheyshowupaspages.Internallyofcourseit'sallverydifferent,buttheapparenteaseofuseisclear.

AddasecondpageLet'screateanotherpage,in pages/contact.js

exportdefault()=>(

<div>

<p>

<ahref="mailto:[email protected]">Contactus!</a>

</p>

</div>

)

Ifyoupointyourbrowserto localhost:3000/contactthispagewillberendered.Asyoucansee,alsothispageisserverrendered.

HotreloadingNotehowyoudidnothavetorestartthe npmprocesstoloadthesecondpage.Next.jsdoesthisforyouunderthehood.

Clientrendering

Next.js

191

Page 192: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Serverrenderingisveryconvenientinyourfirstpageload,forallthereasonswesawabove,butwhenitcomestonavigatinginsidethewebsite,client-siderenderingiskeytospeedingupthepageloadandimprovingtheuserexperience.

Next.jsprovidesa Linkcomponentyoucanusetobuildlinks.Trylinkingthetwopagesabove.

Change index.jstothiscode:

importLinkfrom'next/link'

exportdefault()=>(

<div>

<p>HelloWorld!</p>

<Linkhref="/contact">

<a>Contactme!</a>

</Link>

</div>

)

Nowgobacktothebrowserandtrythislink.Asyoucansee,theContactpageloadsimmediately,withoutapagerefresh.

Thisisclient-sidenavigationworkingcorrectly,withcompletesupportfortheHistoryAPI,whichmeansyourusersbackbuttonwon'tbreak.

Ifyounow cmd-clickthelink,thesameContactpagewillopeninanewtab,nowserverrendered.

DynamicpagesAgoodusecaseforNext.jsisablog,asit'ssomethingthatalldevelopersknowhowitworks,andit'sagoodfitforasimpleexampleofhowtohandledynamicpages.

Adynamicpageisapagethathasnofixedcontent,butinsteaddisplaysomedatabasedonsomeparameters.

Change index.jsto

importLinkfrom'next/link'

constPost=props=>(

<li>

<Linkhref={`/post?title=${props.title}`}>

<a>{props.title}</a>

</Link>

</li>

)

Next.js

192

Page 193: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

exportdefault()=>(

<div>

<h2>Myblog</h2>

<ul>

<li>

<Posttitle="Yetanotherpost"/>

<Posttitle="Secondpost"/>

<Posttitle="Hello,world!"/>

</li>

</ul>

</div>

)

Thiswillcreateaseriesofpostsandwillfillthetitlequeryparameterwiththeposttitle:

Nowcreatea post.jsfileinthe pagesfolder,andadd:

exportdefaultprops=><h1>{props.url.query.title}</h1>

Nowclickingasinglepostwillrendertheposttitleina h1tag:

YoucanusecleanURLswithoutqueryparameters.TheNext.jsLinkcomponenthelpsusbyacceptingan asattribute,whichyoucanusetopassaslug:

Next.js

193

Page 194: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

importLinkfrom'next/link'

constPost=props=>(

<li>

<Linkas={`/${props.slug}`}href={`/post?title=${props.title}`}>

<a>{props.title}</a>

</Link>

</li>

)

exportdefault()=>(

<div>

<h2>Myblog</h2>

<ul>

<li>

<Postslug="yet-another-post"title="Yetanotherpost"/>

<Postslug="second-post"title="Secondpost"/>

<Postslug="hello-world"title="Hello,world!"/>

</li>

</ul>

</div>

)

CSS-in-JSNext.jsbydefaultprovidessupportforstyled-jsx,whichisaCSS-in-JSsolutionprovidedbythesamedevelopmentteam,butyoucanusewhateverlibraryyouprefer,likeStyledComponents.

Example:

exportdefault()=>(

<div>

<p>

<ahref="mailto:[email protected]">Contactus!</a>

</p>

<stylejsx>{`

p{

font-family:'CourierNew';

}

a{

text-decoration:none;

color:black;

}

a:hover{

opacity:0.8;

}

`}</style>

</div>

)

Next.js

194

Page 195: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Stylesarescopedtothecomponent,butyoucanalsoeditglobalstylesadding globaltothestyleelement:

exportdefault()=>(

<div>

<p>

<ahref="mailto:[email protected]">Contactus!</a>

</p>

<stylejsxglobal>{`

body{

font-family:'BentonSans','HelveticaNeue';

margin:2em;

}

h2{

font-style:italic;

color:#373fff;

}

`}</style>

</div>

)

ExportingastaticsiteANext.jsapplicationcanbeeasilyexportedasastaticsite,whichcanbedeployedononeofthesuperfaststaticsitehosts,likeNetlifyorFirebaseHosting,withouttheneedtosetupaNodeenvironment.

TheprocessrequiresyoutodeclaretheURLsthatcomposethesite,butit'sastraightforwardprocess.

DeployingCreatingaproduction-readycopyoftheapplication,withoutsourcemapsorotherdevelopmenttoolingthataren'tneededinthefinalbuild,iseasy.

Atthebeginningofthistutorialyoucreateda package.jsonfilewiththiscontent:

{

"scripts":{

"dev":"next"

}

}

whichwasthewaytostartupadevelopmentserverusing npmrundev.

Nowjustaddthefollowingcontentto package.jsoninstead:

Next.js

195

Page 196: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

{

"scripts":{

"dev":"next",

"build":"nextbuild",

"start":"nextstart"

}

}

andprepareyourappbyrunning npmrunbuildand npmrunstart.

NowThecompanybehindNext.jsprovidesanawesomehostingserviceforNode.jsapplications,calledNow.

OfcoursetheyintegrateboththeirproductssoyoucandeployNext.jsappsseamlessly,onceyouhaveNowinstalled,byrunningthe nowcommandintheapplicationfolder.

BehindthescenesNowsetsupaserverforyou,andyoudon'tneedtoworryaboutanything,justwaitforyourapplicationURLtobeready.

ZonesYoucansetupmultipleNext.jsinstancestolistentodifferentURLs,yettheapplicationtoanoutsideuserwillsimplylooklikeit'sbeingpoweredbyasingleserver:https://github.com/zeit/next.js/#multi-zones

PluginsNext.jshasalistofpluginsathttps://github.com/zeit/next-plugins

StarterkitonGlitchIfyou'relookingtoexperiment,IrecommendGlitch.CheckoutmyNext.jsGlitchStarterKit.

ReadmoreonNext.jsIcan'tpossiblydescribeeveryfeatureofthisgreatframework,andthemainplacetoreadmoreaboutNext.jsistheprojectreadmeonGitHub.

Next.js

196

Page 197: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Next.js

197

Page 198: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

GatsbyGatsbyisaplatformforbuildingappsandwebsitesusingReact

GatsbyisaplatformforbuildingappsandwebsitesusingReact.

ItisoneofthetoolsthatallowyoutobuildonasetoftechnologiesandpracticescollectivelyknownasJAMstack.

GatsbyisoneofthecoolkidsintheFrontendDevelopmentspacerightnow.Why?Ithinkthereasonsare:

theexplosionoftheJAMstackapproachtobuildingWebAppsandWebSitestherapidadoptionoftheProgressiveWebAppstechnologyintheindustry,whichisoneofthekeyfeaturesofGatsbyit'sbuiltinReactandGraphQL,whicharetwoverypopularandrisingtechnologiesit'sreallypowerfulit'sfastthedocumentationisgreatthenetworkeffect(peopleuseit,createsites,maketutorials,peopleknowmoreaboutit,creatingacycle)everythingisJavaScript(noneedtolearnanewtemplatinglanguage)ithidesthecomplexity,inthebeginning,butallowsusaccessintoeverysteptocustomize

Allthosearegreatpoints,andGatsbyisdefinitelyworthalook.

Howdoesitwork?WithGatsby,yourapplicationsarebuiltusingReactcomponents.

Gatsby

198

Page 199: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Thecontentyou'llrenderinasiteisgenerallywrittenusingMarkdown,butyoucanuseanykindofdatasource,likeanheadlessCMSorawebservicelikeContentful.

Gatsbybuildsthesite,andit'scompiledtostaticHTMLwhichcanbedeployedonanyWebServeryouwant,likeNetlify,AWSS3,GitHubPages,regularhostingproviders,PAASandmore.AllyouneedisaplacethatservesplainHTTPpagesandyourassetstotheclient.

ImentionedProgressiveWebAppsinthelist.GatsbyautomaticallygeneratesyoursiteasaPWA,withaserviceworkerthatspeedsuppageloadingandresourcecaching.

YoucanenhancethefunctionalityofGatsbyviaplugins.

InstallationYoucaninstallGatsbybysimplyrunningthisinyourterminal:

npminstall-ggatsby-cli

Thisinstallsthe gatsbyCLIutility.

(whenanewversionisout,updateitbycallingthiscommandagain)

Youcreateanew"HelloWorld"sitebyrunning

gatsbynewmysitehttps://github.com/gatsbyjs/gatsby-starter-hello-world

ThiscommandcreatesabrandnewGatsbysiteinthe mysitefolder,usingthestarteravailableathttps://github.com/gatsbyjs/gatsby-starter-hello-world.

Gatsby

199

Page 200: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Astarterisasamplesitethatyoucanbuildupon.Anothercommonstarteris default,availableathttps://github.com/gatsbyjs/gatsby-starter-default.

Hereyoucanfindalistofallthestartersyoucanuse

RunningtheGatsbysiteAftertheterminalhasfinishedinstallingthestarter,youcanrunthewebsitebycalling

cdmysite

gatsbydevelop

whichwillstartupanewWebServerandservethesiteonport8000onlocalhost.

Gatsby

200

Page 201: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

AndhereisourHelloWorldstarterinaction:

Gatsby

201

Page 202: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

InspectingthesiteIfyouopenthesiteyoucreatedwithyourfavoritecodeeditor(IuseVSCode),you'llfindthereare3folders:

.cache,anhiddenfolderthatcontainstheGatsbyinternals,nothingyoushouldchangerightnowpublic,whichcontainstheresultingwebsiteonceyoubuilditsrccontainstheReactcomponents,inthiscasejustthe indexcomponentstaticwhichwillcontainthestaticresourceslikeCSSandimages

Gatsby

202

Page 203: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

Now,makingasimplechangetothedefaultpageiseasy,justopen src/pages/index.jsandchange"Helloworld!"tosomethingelse,andsave.Thebrowsershouldinstantlyhotreloadthecomponent(whichmeansthepagedoesnotactuallyrefresh,butthecontentchanges-atrickmadepossiblebytheunderlyingtechnology).

Toaddasecondpage,justcreateanother.jsfileinthisfolder,withthesamecontentofindex.js(tweakthecontent)andsaveit.

ForexampleIcreateda second.jsfilewiththiscontent:

importReactfrom'react'

exportdefault()=><div>Secondpage!</div>

andIopenedthebrowsertohttp://localhost:8000/second:

Gatsby

203

Page 204: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

LinkingpagesYoucanlinkthosepagesbyimportingaGatsby-providedReactcomponentcalled Link:

import{Link}from"gatsby"

andusingitinyourcomponentJSX:

<Linkto="/second/">Second</Link>

AddingCSSYoucanimportanyCSSfileusingaJavaScriptimport:

import'./index.css'

YoucanuseReactstyling:

<pstyle={{

margin:'0auto',

padding:'20px'

Gatsby

204

Page 205: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

}}>Helloworld</p>

UsingpluginsGatsbyprovideslotsofthingsoutofthebox,butmanyotherfunctionalitiesareprovidedbyplugins.

Thereare3kindofplugins:

sourcepluginsfetchdatafromasource.CreatenodesthatcanbethenfilteredbytransformerpluginstransformerpluginstransformthedataprovidedbysourcepluginsintosomethingGatsbycanusefunctionalpluginsimplementsomekindoffunctionality,likeaddingsitemapsupportormore

Somecommonlyusedpluginsare:

gatsby-plugin-react-helmetwhichallowstoeditthe headtagcontentgatsby-plugin-catch-linkswhichusestheHistoryAPItopreventthebrowserreloadingthepagewhenalinkisclicked,loadingthenewcontentusingAJAXinstead

AGatsbypluginisinstalledin2steps.Firstyouinstallitusing npm,thenyouaddittotheGatsbyconfigurationin gatsby-config.js.

ForexampleyoucaninstalltheCatchLinksplugin:

npminstallgatsby-plugin-catch-links

In gatsby-config.js(createitifyoudon'thaveit,inthewebsiterootfolder),addtheplugintothe pluginsexportedarray:

module.exports={

plugins:['gatsby-plugin-catch-links']

}

That'sit,thepluginwillnowdoitsjob.

BuildingthestaticwebsiteOnceyouaredonetweakingthesiteandyouwanttogeneratetheproductionstaticsite,youwillcall

Gatsby

205

Page 206: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

gatsbybuild

AtthispointyoucancheckthatitallworksasyouexpectbystartingalocalWebServerusing

gatsbyserve

whichwillrenderthesiteascloseaspossibletohowyouwillseeitinproduction.

DeploymentOnceyoubuildthesiteusing gatsbybuild,allyouneedtodoistodeploytheresultcontainedinthe publicfolder.

Dependingonthesolutionyouchoose,you'llneeddifferentstepshere,butgenerallyyou'llpushtoaGitrepositoryandlettheGitpost-commithooksdothejobofdeploying.

Herearesomegreatguidesforsomepopularhostingplatforms.

Gatsby

206

Page 207: Table of Contents · npm run build : to build the React application files in the build folder, ready to be deployed to a server npm test : to run the testing suite using Jest npm

WrappingupIhopethebookhelpedyougetstartedwithReact,andmaybeitgaveyouaheadstartinexploringsomeofthemostadvancedaspectsofReactprogramming.

That'smyhope,atleast.

Iwillsoonreleaseapracticalonlinecoursetoapplythoseconcepts.Staytuned.

Wrappingup

207