47
ReactJS Škalac, Lorena Master's thesis / Diplomski rad 2017 Degree Grantor / Ustanova koja je dodijelila akademski / stručni stupanj: Josip Juraj Strossmayer University of Osijek, Department of Mathematics / Sveučilište Josipa Jurja Strossmayera u Osijeku, Odjel za matematiku Permanent link / Trajna poveznica: https://urn.nsk.hr/urn:nbn:hr:126:915147 Rights / Prava: In copyright Download date / Datum preuzimanja: 2022-02-09 Repository / Repozitorij: Repository of Department of Mathematics Osijek

ReactJS - zir.nsk.hr

  • Upload
    others

  • View
    21

  • Download
    1

Embed Size (px)

Citation preview

Page 1: ReactJS - zir.nsk.hr

ReactJS

Škalac, Lorena

Master's thesis / Diplomski rad

2017

Degree Grantor / Ustanova koja je dodijelila akademski / stručni stupanj: Josip Juraj Strossmayer University of Osijek, Department of Mathematics / Sveučilište Josipa Jurja Strossmayera u Osijeku, Odjel za matematiku

Permanent link / Trajna poveznica: https://urn.nsk.hr/urn:nbn:hr:126:915147

Rights / Prava: In copyright

Download date / Datum preuzimanja: 2022-02-09

Repository / Repozitorij:

Repository of Department of Mathematics Osijek

Page 2: ReactJS - zir.nsk.hr

Sveuciliste J.J. Strossmayera u Osijeku

Odjel za matematiku

Diplomski studij: Matematika i racunarstvo

Lorena Skalac

ReactJS

Diplomski rad

Osijek, 2017.

Page 3: ReactJS - zir.nsk.hr

Sveuciliste J.J. Strossmayera u Osijeku

Odjel za matematiku

Diplomski smjer: Matematika i racunarstvo

Lorena Skalac

ReactJS

Diplomski rad

Mentor: izv. prof. dr. sc. Domagoj Matijevic

Osijek, 2017.

Page 4: ReactJS - zir.nsk.hr

Sadrzaj

Sazetak 4

Uvod 6

1 O React-u 7

1.1 Zasto biblioteka, a ne framework? . . . . . . . . . . . . . . . . . . . . 7

2 EcmaScript 6 / EcmaScript 7 10

2.1 Kratki osvrt na EcmaScript 6 svojstva koristenih u radu . . . . . . . 10

3 Komponente 14

3.1 Nacini definiranja komponenti . . . . . . . . . . . . . . . . . . . . . . 14

3.2 JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.2.1 Babel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.3 Dodavanje komponente na DOM . . . . . . . . . . . . . . . . . . . . 16

4 Dinamicke komponente 18

4.1 Hijerarhija komponenti i tok podataka unutar nje . . . . . . . . . . . 18

4.1.1 Props parametri komponenti . . . . . . . . . . . . . . . . . . . 18

4.1.2 Renderiranje veceg broja child komponenti . . . . . . . . . . . 19

5 Interaktivno React korisnicko sucelje 21

5.1 Vezanje objekta this unutar funkcija . . . . . . . . . . . . . . . . . . 22

5.2 Koristenje state-a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5.2.1 Kriterij za donosenje odluke treba li podatak biti sadrzan na

state objektu . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5.2.2 Popunjavanje state objekta podacima . . . . . . . . . . . . . . 24

5.2.3 Azuriranje nepromjenjivog state objekta . . . . . . . . . . . . 25

6 Virtualni DOM 27

6.1 Proces azuriranje DOM-a u React aplikacijama . . . . . . . . . . . . 28

7 React u praksi 29

7.1 O aplikaciji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

7.2 Koristene tehnologije i paketi . . . . . . . . . . . . . . . . . . . . . . 31

7.3 Hijerarhija komponenti . . . . . . . . . . . . . . . . . . . . . . . . . . 31

Page 5: ReactJS - zir.nsk.hr

7.4 Izrada podstabla NotePage . . . . . . . . . . . . . . . . . . . . . . . 32

Zavrsetak 43

Literatura 44

Zivotopis 45

Page 6: ReactJS - zir.nsk.hr

4

Sazetak

Cilj ovog rada je citatelja upoznati s osnovama sintakse ReactJS-a, alata i praksa

potrebnih za izradu funkcionalne React aplikacije. Navode se prednosti koje React

donosi kao sto su koristenje virtualnog DOM-a u svrhu azuriranja prikaza aplikacije,

podijela aplikacije na manje ponovne upotrebljive dijelove koje se nazivaju kom-

ponente te automatsko renderiranje koje se dogada na svaku promjenu podataka.

Buduci da su komponente srz svake React aplikacije, veliki dio govori o njihovoj

strukturi, toku podataka medu njima koje se izvrsava pomocu posebnih parame-

tara komponente zvanih props te posebnom state objektu komponente, mjestu koje

sadrzi promijenjive podatke komponente. Kako se spomenuta automatska renderira-

nja ne bi dogadala vise nego sto je potrebno te time narusila performanse aplikacije,

rad takoder ukljucuje kriterije koji ce pomoci u strukturiranju optimalne aplikacije.

Rad zavrsava prakticnim dijelom, jednostavnom Planner aplikacijom za pracenje

zadataka i zapisivanje biljezaka koja ce ukratko, na stvarnom primjeru, prikazati

odradivanje odredenih akcija unutar podstabla React komponenti.

Kljucne rijeci: komponenta, props parametri, state objekt, renderiranje, virtu-

alan DOM

Page 7: ReactJS - zir.nsk.hr

5

Summary

Aim of this paper is to introduce the reader with basics of ReactJS syntax, tools and

practices needed to make a functional React application. Some of Reacts advantages

are listed, for example use of virtual DOM that is used to update application view,

application partitioning to small reusable parts that are called components and auto

re-rendering which is run on every data alteration. Since components are the very

core of every React application, big part of this paper talks about their structure

and data flow between them which is driven by special component parameters called

props and special state object of the component data. In case the aforementioned

auto-renderings wouldn’t happen more than it’s needed, lowering the performance

on the way, paper also includes criterion which will help to structure an optimal

application. Paper concludes with the practical part, a simple Planner application

that can track tasks and mark notes, which will in short present, on the real example,

execution of specific action inside React components subtree.

Keywords: component, props parameters, state object, rendering, virtual DOM

Page 8: ReactJS - zir.nsk.hr

6

Uvod

Danasnje web aplikacije su vecinom interaktivne pa programiranje njihovih ko-

risnickih sucelja moze biti dosta tezak zadatak. U svrhu izvrsavanja korisnikovih

zahtjeva, izazvanih nekom od interakcija, koriste se kombinacije svojstava i funk-

cija cistog JavaScript jezika, JavaScript framework-a i biblioteka. Jedna od cesto

koristenih biblioteka u te svrhe je jQuery. Medutim, kako aplikacije rastu te korisni-

kovi zahtjevi postaju slozeniji, ne zvuci bas idealno da se na svaki korisnikov zahtjev

elementi DOM-a manipuliraju rucno, primjerice na svako dodavanje elemenata u

niz, koji je na sucelju prikazan u obliku tablice, potrebno je i dodati DOM element

koji predstavlja redak tablice, kao sto to zahtjeva jQuery. Buduci da je takav kod

vrlo cesto vezan samo za odredeni zahtjev, kao za prosli primjer specifican broj stu-

paca, klase i slicno, tesko ga je ponovno upotrijebiti te na kraju uopce i pratiti.

Ovakve situcije su ujedno i najveci izvor gresaka web aplikacija, odnosno pojavljuju

se u pokusaju sinkronizacije modela podataka sa DOM-om.

Kako bi se dani problemi rijesili pomocu jednog alata, izraden je ReactJS koji osi-

gurava da svaka promjena nad podacima uzrokuje ponovno renderiranje prikaza

aplikacije. Takvim ce pristupom aplikacija korisniku u svakom trenutku prikazivati

njeno stvarno stanje.

Osim dobrobiti koje donosi aplikaciji, ucenje i koristenje React-a ce i svakog progra-

mera uciniti uspjesnijim. Naime, zbog React-ovog poticanja na koristenje svojstava

koje dolaze iz najnovijih verzija JavaScript-a te koncepta funkcijskog programira-

nja, programer ce postati bolji u koristenju JavaScript programskog jezika. Takoder,

buduci da je strukturiran kao skupina manjih komponenti koje se nastoje kreirati

tako da budu odgovorne za jedan dio funkcionalnosti, React ce programera poduciti

boljem strukturiranju aplikacija.

Page 9: ReactJS - zir.nsk.hr

7

1 O React-u

React su kreirali inzenjeri Facebook-a u svrhu dobivanja aplikacije koja ima sljedeca

dva bitna svojstva:

• Skalabilnost - sposobnost sustava da nastavi dobro funkcionirati neovisno o

promjeni njegove velicine.

• Odrzivost - sposobnost sustava da se nakon dozivljenog pada lako i brzo vrati

u operativno stanje.

Objavljen je 2013. godine kao JavaScript biblioteka za kreiranje korisnickih sucelja.

1.1 Zasto biblioteka, a ne framework?

Iako ima mnoge odlike framework-a mnogi su protiv misljenja da je React kom-

pletan framework. Sluzbena stranica ga navodi kao JavaScript biblioteku za izradu

korisnickih sucelja. Kako bi se poblize shvatio razlog donosenja ove odluke, potrebno

je opisati kljucne razlike izmedu framework-a i biblioteke.

JavaScript framework je arhitekturalni pattern pisan u JavaScript program-

skom jeziku koji definira dizajn aplikacije. To znaci da ce se pri izradi aplikacije

koja koristi framework nuzno morati pratiti struktura koju on specificira. Neki od

poznatih JavaScript framework-a su:

• AngularJS

• Knockout.js

• Ember.js

• Vue.js

JavaScript biblioteka je skup funkcija pisanih u JavaScript programskom jeziku

cije koristenje olaksava izradu JavaScript aplikacija. Moze ih napisati svatko, obje-

diniti u paket te dati drugima na koristenje. Obicno zamjenjuju dijelove koda koji

se cesto ponavljaju. Neki od poznatih JavaScript biblioteka su:

• jQuery

Page 10: ReactJS - zir.nsk.hr

8

• D3.js

• Moment.js

• Underscore.js

Programeri pisu kod za framework kako bi izradio aplikaciju, dok biblioteku koriste

kako bi napisala kod kojim ce moci izraditi aplikaciju. To je ujedno i kljucna razlika

izmedu framework-a i bilioteke.

Facebook inzenjeri su pri kreiranju ReactJS-a izabrali koristenje drugacijeg pristupa

od onog koji se koristi u siroko poznatom AngularJS-u i ostalim MVC frameworcima.

Primjerice u Angular-u 1, izradivanje aplikacije se sastoji od izrade HTML template-

a, kontrolera koji njima upravljaju, servisa koji sadrze logiku koja se moze koristiti

medu kontrolerima i direktiva koje predstavljaju ponovno upotrebljive dijelove koda.

Koristeci samo Angular 1 i prateci njegovu strukturu moguce je izraditi cijelu funk-

cionalnu aplikaciju bez potrebe za pomocnim bibliotekama. S druge strane, React

nema posebne strukture. Fokusiran je samo na view sloj aplikacije te ce zahtijevati

koristenje ostalih biblioteka kako bi se mogla izraditi funkcionalna React aplikacija.

To znaci da je React jedna velika JavaScript biblioteka te se kao takva moze koristiti

u kombinacijama s ostalim bibliotekama i frameworcima.

Iako nije jedan od njih, cesto se moze pronaci u usporedbama performansi razlicitih

JavaScript framework-a. Iz razlicitih mjerenja koja su provedena u te svrhe poka-

zalo se da je React u rangu s najpoznatijima od njih od kojih neke cak i nadmasuje.

Sljedeca slika, dobivena primjenom filtera na stranici:

http://www.stefankrause.net/js-frameworks-benchmark6/webdriver-ts-results/

table.html,

prikazuje rezultate mjerenja renderiranja view-a nakon izvedbe odredenih akcija u

cetiri najpoznatija framework-a te React-u. Rezultati su izrazeni u milisekundama.

Page 11: ReactJS - zir.nsk.hr

9

Slika 1: Vrijeme izvrsavanja akcija u odredenim frameworcima izrazeno u milisekun-dama

Uz to sto ima veliku brzinu renderiranja, iz slike se moze vidjeti da ona ne ovisi

o velicini podataka na kojemu se izvodi. Naime, mjerenje navodi da geometrijska

sredina usporavanja React-a, obzirom na velicinu podataka, iznosi 1.13 sto znaci da

je Facebook-ova namjera za dobivanje skalabilne biblioteke bila uspjesna. Razlog

tome je sto React, pri azuriranju DOM-a, azurira samo ono sto se stvarno pro-

mijenilo te pritom koristi virtualan DOM koji posjeduje znatno jeftinije operacije

od ekvivalntnih na pravom DOM-u. Kako ga je moguce koristiti u kombinaciji sa

drugim frameworcima, pozeljno ga je koristiti kao view sloj aplikacija koja koriste

framework-e sa slabijim performansama na tom podrucju.

Page 12: ReactJS - zir.nsk.hr

10

2 EcmaScript 6 / EcmaScript 7

Kao sto je u prethodnom poglavlju zakljuceno, ReactJS je biblioteka. Pisana je u

Javascript skriptnom programskom jeziku kojeg je 1995. godine kreirao tadasnji

inzenjer Netscape-a Brendan Eich. Sluzbeno je objavljen 1996. godine zajedno s

Netscape-om 2, web preglednikom tvrtke Netscape. Originalan naziv mu je bio Li-

veScript no ubrzo je preimenovan u JavaScript u svrhu stjecanja popularnosti kroz

tadasnju popularnost Java programskog jezika. Iz tog razloga ljudi mijesaju ta dva

jezika iako imaju malo toga zajednickog.

Danas je JavaScript najcesce koristen jezik u izradi web aplikacija te je uz HTML i

CSS jedna od tri jezgrene tehnologije vecine web aplikacija. Izvrsava se na klijent-

skoj strani aplikacije u svrhu definiranja kako ce se ona ponasati u trenutku pojave

odredenog dogadaja. Potrebno je naglasiti da se JavaScript koristi i u okolinama

koje ne ukljucuju pojavu web preglednika kao sto je primjerice serverski orjentirano

okruzenje Node.js. Posjedovanje znanja o ovom jeziku postala je bitna i neizbjezna

vjestina svakog web ili mobile programera.

Ovakvo svjetsko prihvacanje JavaScript-a, kao primarnog programskog jezika kli-

jentske strane web aplikacija, dovelo je do formacije njegovog standarda, odnosno

specifikacije koja je nazvana Ecmascript ili skraceno ES. Trenutno aktualno izdanje

je EcmaScript 7 na koje se moze gledati kao na sedmu verziju JavaScript program-

skog jezika.

EcmaScript 6 standard je dozivio znacajno prosirenje sa cak oko 20-ak skupina novih

svojstava dok je za usporedbu EcmaScript 7 imao tek dva. React potice koristenje

svojstva najnovijih verzija JavaScript-a stoga ce u radu ona biti cesto koristena.

Potrebno je naglasiti da, iako je aktualan EcmaScript 7 standard, kada bude rijec

o novim svojstvima u radu referirat ce se na EcmaScript 6 svojstva jer vecina njih

dolazi iz tog standarda.

2.1 Kratki osvrt na EcmaScript 6 svojstva koristenih u radu

Class

JavaScript je jezik u kojemu ne postoje klase kao sto je to inace u ostalim objektno-

Page 13: ReactJS - zir.nsk.hr

11

orjentiranim jezicima. Kada je rijec o nasljedivanju, u JavaScript-u objekt nasljeduje

objekt koristenjem sintakse bazirane na prototyp nasljedivanju. Izlaskom ES6 stan-

darda uvodi se rijec class u JavaScript jezik. Nova class sintaksa ne uvodi novi

model nasljedivanja vec samo omogucuje jednostavniju i intuitivniju sintaksu za

kreiranje objekta (kasnije u tekstu klasa) i proces postojeceg nasljedivanja. Klase

se, kao i u vecini ostalih objektno orjentiranih programskih jezika, kreiraju pomocu

rijeci class. Svaka na ovaj nacin kreirana klasa treba imati metodu constructor()

koja se poziva u trenutku kada se instancira novi objekt te klase koristeci sintaksu

new className(). Prosirenja klasa su moguca koristenjem sintakse Child extends

Parent.

U React-u, ovo svojstvo sluzi za kreiranje komponenti, neovisnih i ponovno upo-

otrebljivih dijelova koda koji su srz svake React aplikacije.

Const & Let

Obje nove kljucne rijeci let i const sluze za deklariranje varijabla.

Const sluzi za deklariranje konstanti, odnosno nepromjenjivih varijabla kojima se

kasnije ne zeli dodijeliti nova vrijednost. Deklarira li se konstanta na ovaj nacin te

joj se zatim pokusa promijeniti vrijednost, program ce upozoriti na pogresku.

1. const pi = 3.14;

2. pi = 3.14159265359; // Assignment to constant variable

U slucaju kada varijabla moze mijenjati vrijednost, za njeno deklariranje se koristi

rijec let. Ovakvo deklariranje varijable ima slicna svojstva kao pomocu standardne

rijeci var. Razlika je u tome sto se deklariranjem pomocu rijeci let podrucje posto-

janja varijable ogranicava na blok koda u kojem je deklarirana cime se mogu izbjeci

nezeljene pogreske u aplikaciji.

1. let x = 0;

2. if (true){

3. var y = 1;

4. let z = 2;

5. }

6. console.log(x); // 0

7. console.log(y); // 1

8. console.log(z); // z is not defined

Page 14: ReactJS - zir.nsk.hr

12

Arrow funkcije

ES6 uvodi novu sintaksu za pisanje anonimnih funkcija koristenjem arrow funkcija.

Dobile su naziv po ⇒ znaku koji pruza sazetost definicije funkcije. Arrow funkcije

u JavaScript-u su zapravo funkcije koje su u drugim programskim jezicima poznate

pod nazivom lambda funkcije. Njihova prednost u React-u, osim sazetosti, je u u

nacinu vezanja this objekta unutar funkcija. One nemaju this objekt te zbog toga

koriste this objekt parent objekta. U React-u, koristenje arrow funkcija zbog toga

ce automatski vezati objekt this, unutar funkcija koje ne dolaze iz React biblioteka,

na komeponentu unutar koje je funkcija definirana.

Sintaksa definiranja arrow funkcija je takva da se prije znaka ⇒ stavljaju parametri

fukcije, a iza njega tijelo funkcije.

1. var sum = (a,b) => {

2. return a + b;

3. };

4. var sum2 = (a,b) => (a + b);

5.

6. console.log(sum(1,2)); // 3

7. console.log(sum2 (1,2)); // 3

Ukoliko u tijelu funkcije postoji samo return izraz, definicija funkcije se moze do-

datno sazeti tako da se rijec return ispusti te se rezultat koji zeli biti vracen stavi u

okrugle zagrade iza znaka ⇒.

Object.assign()

Metoda Object.assign() se koristi za kopiranje vrijednosti svojstava s jednog ili vise

izvora objekta na ciljani objekt. Prima bilo koji broj argumenata s naznakom da

prvi referencira ciljani objekt dok ostali izvorne objekte. Metoda kao rezultat vraca

ciljani objekt.

1. const source = {

2. name: "Test",

3. value: 0

4. };

5.

6. var a = Object.assign ({}, source , {

7. value: 1

8. });

9.

Page 15: ReactJS - zir.nsk.hr

13

10. console.log(a);

11. // Object {

12. // "name": "Test",

13. // "value": 1

14. //}

U prethodnom primjeru, prvi objekt pridruzen funkciji Object.assign() predstavlja

novi objekt kojeg ce funkcija vratiti, drugi predstavlja objekt s kojega ce kopirati

svojstva na prvi novostvoreni objekt te treci predstavlja objekt koji ce azurirati no-

vostvoreni objekt s kopiranim vrijednostima drugog objekta.

Kao rezultat dobiven je objekt koji je jednak izvornom objektu s azuriranom vri-

jednoscu svojstava.

Prethodno je spomenuto da se varijablama koje su definirane sa rijeci const ne moze

ponovno dodijeliti vrijednosti pa je ova metoda prikladna kada se radi s konstantnim

podacima.

Page 16: ReactJS - zir.nsk.hr

14

3 Komponente

Srz svake React aplikacije cine komponente. One su samostalne i ponovno upotreb-

ljive cjeline koda koje sadrze markup, logiku te stil na jednom mjestu. Na njih se

moze gledati kao na funkcije jer primaju ulazne props parametre te kao izlaz vracaju

React element koji opisuje sto se treba prikazati na zaslonu. U trenutku kada se

ulazni parametar komponente promijeni, React ponovno renderira tu komponentu.

To svojstvo osigurava da izgled komponente na zaslonu bude jednak onome sto joj

se proslijedi, odnosno da za dani ulaz uvijek daje isti izlaz.

Komponente treba izradivati na nacin da je svaka odgovorna za samo jedan dio

funkcionalnosti. Ukoliko se u kodu naide na neku za koju vrijedi suprotno to sugerira

da se ona moze razbiti na vise komponenti. Takva podjela odgovornosti ucinit ce

komponente jednostavnima te omoguciti da budu pogodne za ponovnu upotrebu.

3.1 Nacini definiranja komponenti

U React-u, komponente se mogu definirati na dva nacina:

Kao EcmaScript klase

U ovom slucaju komponenta je EcmaScript klasa koja nasljeduje React klasu Re-

act.Component. Sintaksa kreiranja komponente koristeci ovaj nacin je sljedeca:

1. class MyComponent extends React.Component{

2. render () {

3. return (

4. <p> Hello world! </p>

5. );

6. }

7. }

Koristenjem React.createClass() metode

U ovom slucaju za kreiranje komponente koristi se ugradena React metoda create-

Class(). Sintaksa kreiranja komponenata koristeci ovaj nacin je sljedeca:

1. const MyComponent = React.createClass ({

2. render (){

Page 17: ReactJS - zir.nsk.hr

15

3. return(

4. <p> Hello world! </p>

5. );

6. }

7. });

Oba nacina deklariranja komponenti su prihvatljiva te su razlike minimalne. Razlog

postajanja dva nacina je taj sto je React nastao u vrijeme kada JavaScript nije imao

ugraden sustav za kreiranje klasa pa je uveo svoj React.createClass. S pojavom Ec-

maScript 6 standarda komponente je moguce kreirati i koristeci class sintaksu.

React metoda render() koristena u prethodnim primjerima je jedina nuzna metoda

React komponente. React koristi vracenu vrijednost te metode kako bi zakljucio sto

treba renderirati na zaslonu aplikacije.

3.2 JSX

U primjerima kreiranja komponenti moze se uociti da izraz koji metoda render()

vraca ne izgleda kao tradicionalni JavaScript. Ona vraca dio koda koji je napisan

pomocu JSX-a. Skracenica JSX dolazi od izraza JavaScript Syntax Extenstion te

se radi o ekstenziji sintakse JavaScript-a koju je napravio Facebook kako bi pisanje

markupa komponenti bilo omoguceno u poznatoj HTML sintaksi. Sljedeci primjer

prikazuje dio koda za kreiranje React elementa pomocu JSX ekstenzije:

1. <div className="red -box">

2. <p> Hello world. </p>

3. </div >

Koristenje JSX-a nije nuzno te se kao alternativa moze koristiti direktno cisti JavaS-

cript. U tom slucaju za kreiranje React elemenata koristi se React.createElement()

funkcija koja prima tri argumenta. Prvi argument oznacava tip elementa, drugi svoj-

stva elementa te treci djecu elementa. Ekvivalentan React element iz prethodnog

primjera bez koristenja JSX ekstenzije pisao bi se na sljedeci nacin:

1. React.createElement(’div’, {className: ’red -box’},

2. React.createElement(’p’, null , ’Hello world.’)

3. );

Nacin kreiranja React elemenata koristeci React.createElement() funkcije je pogodan

Page 18: ReactJS - zir.nsk.hr

16

za male komponente no u situacijama kada je komponenta sastavljena od mnogo ug-

njezdenih elemenata, sintaksa moze postati necitljiva te se tada preporuca koristenje

JSX ekstenzije.

Buduci da preglednici ne znaju procitati JSX, on je pretvoren u JavaScript pomocu

dodatnih alata. Najcesce koristen alat za ovu pretvorbu je Babel.

3.2.1 Babel

Babel je JavaScript kompajler koji razumije JSX. On pretvara JSX sintaksu u Va-

nilla ES5 JavaScript koji ce svaki preglednik moci interpretirati. Takoder, vecina

web preglednika ne podrzava sva svojstva EcmaScript 6 standarda te se u svrhu

njihove pretvorbe u ES5 sintaksu takoder koristi Babel.

Buduci da ce JavaScript konstantno evoluirati, alat kao Babel je pozeljan u projektu

jer ce programeri uvijek moci iskoristiti prednosti koje im pruzaju nova svojstva. U

suprotnom ce na to morati pricekati jer je web preglednicma potrebno duze vrijeme

za azuriranje strojeva koji omogucuju direktno koristenje novih svojstava jezika.

3.3 Dodavanje komponente na DOM

Nakon izrade React komponenti, potreban je nacin na koji ce se one povezati sa

vanjskim svijetom aplikacije. U tu svrhu koristi se ReactDOM.render() funkcija

koja dolazi iz react.dom biblioteke.

Nacin kojim ce se React-u reci da komponenta treba biti umetnuta na odredeni dio

DOM-a je ta da se ReactDOM.render() funkciji prosljede dva argumenta, prvi koji

oznacava React element koji se zeli renderirati te drugi koji govori na koje mjesto u

DOM-u se prvi argument zeli renderirati.

Pretpostavljajuci da negdje u DOM-u aplikacije postoji element sa id atributom

myApp, sintaksa renderiranja komponente MyComponent unutar tog elementa je

sljedeca:

1. ReactDOM.render(<MyComponent />,

2. document.getElementById(’myApp’));

Nakon ovog koraka komponenta ce biti vidljina na prikazu aplikacije.

Page 19: ReactJS - zir.nsk.hr

17

U primjeru se takoder vidi razlika u pisanju React elemenata i HTML tagova u

JSX sintaksi. Naime, HTML tagovi zapocinju malim slovom dok React elementi

zapocinju velikim slovom. Sintaksom <MyComponent /> komponenta MyCompo-

nent je pretvorena u React element te kao takva prosljedena ReactDOM.render()

funkciji koja ce ju znati umetnuti u pravi DOM.

Page 20: ReactJS - zir.nsk.hr

18

4 Dinamicke komponente

Dinamicke komponente su komponente koje ce se dinamicki renderirati ovisno o

podacima koji su im prosljedeni.

4.1 Hijerarhija komponenti i tok podataka unutar nje

Medu komponentama u React aplikacijama postoji hijerarhija pa postoje parent i

child komponente. Kako bi neka komponenta B postala child komponenta kompo-

nenti A, potrebno ju je smjestiti u render() funkciju komponente A. Komponenta

A tada postaje parent komponenta komponenti B.

Tok podataka unutar takve strukture uvijek ide od vrha prema dnu sto znaci da ce

svaka parent komponenta prosljedivati podatke child komponentama. Takva struk-

tura ujedno omogucuje parent komponenti da dinamicki renderira bilo koji broj

child komponenti od kojih ce svaka imati svoje jedinstvene atribute. Prosljedivanje

podataka izmedu komponenti omoguceno je pomocu parametara koji se nazivaju

props.

4.1.1 Props parametri komponenti

U trenutku kada parent komponenta renderira child komponentu moze joj pros-

lijediti props parametre o kojima ona ovisi. Prosljedivanje podataka se provodi

na nacin da se na child komponentu, koja se nalazi unutar render() funkcije pa-

rent komponente, doda atribut te njemu pridruzena vrijednost pri cemu ce atribut

oznacavati ime prop parametra. U sljedecem primjeru ParentComponent kompo-

nenta prosljeduje ChildComponent komponenti props parametre title i imageUrl.

1. class ParentComponent extends React.Component{

2. const imageUrl = "someImage.jpg";

3. render (){

4. return(

5. <ChildComponent

6. title = "Hello world!"

7. imageUrl = {imageUrl}

8. />

9. );

10. }

11. }

Generalno, u JSX-u svaka vrijednost atributa mora biti odvojena:

Page 21: ReactJS - zir.nsk.hr

19

• Ili viticastim zagradama - govore JSX-u da se unutar njih nalazi JavaScript

izraz. Izraz se prvo rjesava te se vrijednost koju on vraca pridruzuje atributu.

• Ili navodnicima - koriste se za stringove koji se direktno pridruzuju atributu.

Svrha toga sto parent komponenta salje podatke child komponenti je ta da ih ona na

neki nacin koristi. U Reactu, komponenta moze pristupiti svim prosljedenim props

parametrima pomocu objekta this.props. this.props objekt iz prethodnog primjera,

unutar ChildComponent komponente je sljedeci:

1. this.props = {

2. title: "Hellow world!",

3. imageUrl: "someImage.jpg"

4. }

Svojstva this.props objekta se mogu koristiti unutar child komponente kako bi ren-

derirala dijelove sucelja koji ovise o njihovim vrijednostima. Koriste se na nacin da

se na mjestu, gdje se zele umetnuti, zapisu unutar viticastih zagrada. Primjerice,

ako se vrijednosti svojstava this.props objekta komponente ChildComponent zele

umetnuti kao sadrzaj ili atribut nekog elementa, provodi se na sljedeci nacin:

1. class ChildComponent extends React.Component{

2. render (){

3. return(

4. <div > {this.props.title} </div >

5. <img src={this.props.imageUrl} />

6. );

7. }

8. }

Iz primjera je vidljivo da je sintaksa kojom se vrijednost prop parametra umece kao

sadrzaj elementa jednaka sintaksi za pridruzivanje vrijednosti atributu elementa.

This objekt unutar render() funkcije povezan je s klasom React komponente u kojoj

se nalazi pa kada se pristupa this.props objektu unutar render() funkcije pristupa

se props parametrima te komponente.

4.1.2 Renderiranje veceg broja child komponenti

Kako bi neka komponenta renderirala veci broj child komponenti, prvi korak je da

generira niz tih komponenti i spremi ih u neku vrijablu. U tu svrhu se koristiti

Page 22: ReactJS - zir.nsk.hr

20

map() funkcija.

map() funkcija prolazi nizom elemenata nad kojim je pozvana te funkciju, koju ona

prima kao argument, poziva na svakom elementu tog niza. Tek kada zavrsi s posljed-

njim elementom niza, map() funkcija vraca novi niz koji sadrzi vracene vrijednosti

izvrsene argument funkcije na svakom elementu niza.

U slucaju generiranja niza child komponenti, map() funkcija se poziva na nizu poda-

taka koji opisuju child komponente te za svaki element tog niza prosljedena funkcija

kreira child komponentu. Krajnji rezultat ove operacije biti ce novokreirani niz child

komponenti cija velicina je jednaka broju elemenata niza podataka koji je opisivao

te komponente.

Nakon generiranja niza child komponenti preostaje reci render() funkciji da vrati

niz novonastalih komponenti na nacin koji je prikazan u sljedecem primjeru.

1. class ComponentList extends React.Component{

2. render (){

3. const childComponents = childArray.map(( child) => (

4. <ChildComponent

5. key={ child.id}

6. title={ child.title}

7. imageUrl ={ child.imagUrl}

8. />

9. ));

10. return(

11. <div id="childComponents">

12. {childComponents}

13. </div >

14. );

15. }

16. }

U primjeru je koristen specijalan prop parametar komponenti koji se naziva key. U

slucaju renderiranje vise child komponenti preporuca se njegovo koristenje jer ga

React koristi kako bi kreirao jedinstvenu vezu za svaku instancu komponente. To ce

dodatno optimizirati algoritam pretrazivanja koji React koristiti kako bi pronasao

elemente koji se trebaju azurirati. Kako vrijednost key parametra treba biti jedins-

tvena, za nju se najcesce koristi identifikator objekta.

Page 23: ReactJS - zir.nsk.hr

21

5 Interaktivno React korisnicko sucelje

Korisnicka sucelja danasnjih web aplikacija su vecinom interaktivna. Ona omogucuju

korisniku da putem neke vrste interaktivnog dogadaja posalje zahtjev aplikaciji. Pri-

mjerice, na klik dugmeta za azuriranje neke komponente korisnik ocekuje da se otvori

forma za azuriranje.

U React-u, child komponente mogu citati props parametre koji su im prosljedeni,

ali ih ne mogu modificirati. Razlog tome je sto one nisu njihovi vlasnici vec su to

parent komponente. Za child komponente props parametri sluze samo za citanje te

su s njihovog aspekta oni nepromjenjivi podaci. Takva struktura podrzava React-

ovu ideju o toku podataka u jednom smjeru sto znaci da ukoliko se zeli napraviti

neka promjena nad podacima da ce se oni mijenjati od vrha hijerarhije te se nakon

toga ponovno prosljedivati prema nizim razinama.

Buduci da se interaktivni dogadaj korisnika najcesce dogada na nekoj od child kom-

ponenti, potreban je nacin na koji ce ona signalizirati taj zahtjev parent komponenti,

koja je vlasnik podataka nad kojima zahtjev zeli izvrsiti promjenu. U tu svrhu pa-

rent komponenta ce putem prop parametra, komponenti na kojoj se izvodi zahtjev,

uz podatke prosljediti i funkciju koja se nazivna callback. Takva funkcija ima samo

jednu namjenu i to je komunikacija child komponente s parent komponentom. U

trenutku kada korisnik posalje zahtjev, komponenta na kojoj se on izvodi ce pozvati

prop parametar na kojem se nalazi callback funkcija. Poziv ce teci sve do parent

komponente unutar koje ce callback funkcija pozvati funkciju unutar koje je defi-

nirana logika za odradivanje zeljenog zahtjeva. Nakon sto se ova funkcija izvrsi te

napravi zeljene modifikacije nad podacima, parent komponenta ce azurirane podatke

ponovno proslijediti prema child komponentama.

Callback funkcija koja sluzi za komunikaciju child komponenti s parent komponen-

tama je jedna od onih koje ne dolaze iz React biblioteka te se unutar takvih this

objekt ne referencira na komponentu. Razlog tome je sto funkcije koje ne dolaze iz

React biblioteka imaju razlicit nacin vezanja this objekta unutar funkcije.

Page 24: ReactJS - zir.nsk.hr

22

5.1 Vezanje objekta this unutar funkcija

U JavaScript-u specijalan this objekt ima razlicito vezanje ovisno o kontekstu. Pri-

mjerice, unutar render() funkcije this objekt referencira na komponentu u kojoj se

nalazi dok unutar spomenute callback funkcije, koja sluzi za komuniciranje child

komponente sa parent komponentom, referencira na null vrijednost. Razlog tome je

sto unutar svake funkcije iz React biblioteka, kao sto je render(), React automatski

veze this objekt unutar funkcije na komponentu. Za svaku drugu funkciju vezanje

objekta this je potrebno izvesti manualno. To se moze postici na dva nacina:

Unutar konstruktora

Constructor() je jedinstvena funkcija JavaScript klase koja se poziva svaki put kada

se radi nova instanca te klase. Buduci da je svaka komponenta React klasa, prvo

sto ce React napraviti pri incijaliziranju komponente je to da ce pozvati konstruktor

skupa sa props parametrima komponente. Zbog tog svojstva upravo je konstruktor

mjesto gdje se treba obaviti vezanje objekta this unutar funkcije na komponentu.

Nacin na koji se to provodi je sljedeci:

1. class MyComponent extends React.Component{

2. constructor(props){

3. super(props);

4.

5. this.myFunction = this.myFunction.bind(this);

6. }

7. };

Koristeci paket Babel-a i arrow funkcije

Standardna sintaksa za definiranje anonimnih funkcija ce vezati objekt this, koji

se koristi unutar funkcije, na globalan objekt. Ukoliko se za definiranje anonimnih

funkcija koriste arrow funkcije uz ukljucen transfrom-class-properties Babel paket,

one ce vezati isti taj objekt unutar zatvorenog konteksta, u ovom slucaju na kom-

ponentu. U tom slucaju objekt this nije potrebno vezati manualno sto uvelike

pojednostavljuje posao.

Uvodenjem callback funkcija omoguceno je slanje zahtjeva za modifikacijom nad

podacima od child komponente do parent komponente koja je vlasnik tih podataka.

Page 25: ReactJS - zir.nsk.hr

23

Kako bi se ta modifikacija i izvrsila, unutar komponente je potrebno mjesto na kojem

ce se to odvijati. U React-u, to je objekt koji se naziva state.

5.2 Koristenje state-a

U React-u postoje dva tipa podataka o kojima komponenta ovisi. To su props i state

objekti. Props objekt prosljeden je od parent komponente te je za child komponentu

nepromjenjiv kroz cijeli njen zivotni ciklus. Za podatke koji ce se mijenjati koristi

se state objekt. On je privatan za komponentu te se moze azurirati pomocu funkcije

setState().

Buduci da je svaka komponenta renderirana kao funkcija ovisna o this.props i this.state

objektima, state ima vazno svojstvo u React-u jer ce se na svako njegovo azuriranje

komponenta ponovno renderirati. Renderiranje komponenti je deterministicki pro-

ces jer ce za dani skup svojstava this.props i this.state objekta komponenti, kompo-

nenta uvijek biti renderirana na isti nacin. Ovaj pristup omogucava konzistenciju

korisnickog sucelja sa stvarnim stanjem podataka.

Radi performansi te jednostavnosti aplikacije, state objekt komponente treba biti

prezentiran sa sto manje izvora podataka. U tu svrhu moze se koristiti sljedeci kri-

terij koji ce dati odgovor na to treba li promatrani podatak biti sadrzan na state

objektu.

5.2.1 Kriterij za donosenje odluke treba li podatak biti sadrzan na stateobjektu

• Je li promatrani podatak prosljeden od parent komponente putem props pa-

rametara? Ako je odgovor pozitivan, vjerojatno nije sadrzan na state objektu.

• Mijenja li se promatrani podatak s vremenom? Ako je odgovor negativan,

vjerojatno nije sadrzan na state objektu.

• Moze li se promatrani podatak izracunati na temelju nekih drugih podataka

sadrzanih na state objektu ili na temelju props parametara u danoj kompo-

nenti? Ako je odgovor pozitivan, nije sadrzan na state objektu.

Page 26: ReactJS - zir.nsk.hr

24

Nakon zakljucivanja koji podaci trebaju biti sadrzani na state objektu, potrebno je

zakljuciti u kojim komponentama oni trebaju zivjeti. Stoga za svaki podatak state

objekta, treba izvrsiti sljedece:

1. Identificirati sve komponente koje renderiraju kod koji ovisi o state objektu.

2. Pronaci zajednicku vlasnik komponentu, odnosno komponentu iznad svih kom-

ponenti koje trebaju state objekt u hijerahiji.

3. State objekt treba zivjeti na zajednickoj vlasnik komponenti. Ukoliko iz ne-

kog razloga nema smisla da state objekt zivi u toj komponenti, state objekt

treba zivjeti u novoj komponenti koja ce se dodati u hijerarhiju iznad za-

jednicke vlasnik komponente. Njena namjena ce naprosto biti posjedovanje

state objekta.

5.2.2 Popunjavanje state objekta podacima

Praksa je uvijek postaviti inicijalno stanje state objekta radi izbjegavanja pogreske

koju React javlja kada se state objekt jos nije popunio podacima. Buduci da je cons-

tructor() metoda komponente koja se prva poziva pri njenom kreiranju, predstavlja

najbolje mjesto za definiranje inicijalnog stanja state objekta. Sljedeci primjer pri-

kazuje inicijalno stanje state objekta s podatkom data koji predstavlja prazan niz

podataka.

1. constructor(props){

2. super(props);

3.

4. this.state = {

5. data: []

6. };

7. };

Ukoliko se u komponenti ne koristi konstruktor u druge svrhe, uz dodatno ukljucen

Babel paket transform-class-properties, inicijalno stanje state objekta moze biti de-

finirano na pocetku definicije komponente.

U ovom trenutku komponenta je sposobna koristiti podatke state objekta no buduci

da je jedini podatak na state objektu prazan niz, niti jedna komponenta na nizoj

razini hijerarhije se nece renderirati. Podatke sadrzane na state objektu je potrebno

popuniti nakon sto se komponenta montira na DOM. U tu svrhu koristi se React-ova

Page 27: ReactJS - zir.nsk.hr

25

metoda componentDidMount() koje se poziva upravo u tom trenutku.

Jedino mjesto gdje se state objektu pridruzuju podaci pomocu znaka jednakosti je

prilikom definiranja inicijalnog stanja. Za ostale se modifikacije koristi setState()

metoda.

1. componentDidMount (){

2. this.setState ({

3. data: [1, 2, 3]

4. });

5. }

Kronoloski slijed dogadaja koji nastupaju od postavljanja inicijalnog state objekta

do njegovog azuriranja:

1. Komponenta se montira na stranicu sa podacima koji se nalaze na inicijalnom

state objektu.

2. State objekt se puni podacima.

3. Komponenta se ponovno renderira sa popunjenim podacima.

4. Podaci se prikazuju na zaslonu.

Prethodni koraci se dogadaju u brzini koja je neprimjetna korisniku.

5.2.3 Azuriranje nepromjenjivog state objekta

Unatoc tome sto komponenta moze azurirati state objekt, preporuca se smatrati

state objekt nepromjenjivim objektom. Kako bi se ipak udovoljilo korisnikovom

zahtjevu za modifikacijom podataka, koji su sadrzani na state objektu, koriste se

JavaScript funkcije koje, umjesto da rade modifikacije na prosljedenom objektu,

vracaju novi. Najcesce takve funkcije koje se koriste u svrhu provedbe CRUD ope-

racija nad podacima su:

• concat() – metoda koja spaja dva ili vise niza. Koristi se za dodovanje novih

elemenata u niz.

1. var immutableArray = [1,2,3]

2. var newArray = immutableArray.concat ([4]);

3. console.log(immutableArray); // [1,2,3]

4. console.log(newArray); // [1,2,3,4]

Page 28: ReactJS - zir.nsk.hr

26

• filter() – metoda koja se provodi na nizu te kao argument prima funkciju koja

sluzi kao test. Kao rezultat vraca novi niz koji sadrzi elemente niza elemenata

na kojoj je pozvana te koji su prosli prosljedenu test funkciju. Koristi se za

brisanje elemenata niza.

1. var immutableArray = [1,2,3];

2. var newArray = immutableArray.filter ((x => x % 2 !== 0));

3. console.log(immutableArray); // [1,2,3]

4. console.log(newArray); // [1,3]

• Object.assign() – metoda objasnjena unutar poglavlja EcmaScript 6 svoj-

stva. Koristi se za azuriranje svojstava postojecih podataka.

Page 29: ReactJS - zir.nsk.hr

27

6 Virtualni DOM

DOM je skracenica za Document Object Model. Apstrakcija je strukturiranog tek-

sta programerima znanog kao HTML kod. Elementi HTML-a predstavljaju cvorove

u DOM-u. Za jedan HTML moguce je imati vise DOM objekata, primjerice kada je

ista stranica ucitana na vise tabova web preglednika.

Prema strukturi HTML dokumenta, DOM je uvijek strukturiran kao stablo. Takva

struktura omogucuje lak no ne i brz prijelaz po njemu. Stabla DOM-a danasnjih

aplikacija su ogromna te buduci da je vecina njih dinamicka, manipulacija DOM-a

cini njihovu srz. Uz to sto je jedna od najskupljih operacija DOM-a, vecina fra-

meworka azurira DOM vise nego sto je potrebno.

Primjerice, ukoliko se na listi od deset zadatka zeli oznaciti jedan kao zavrsen,

vecina frameworka ce nakon toga ponovno izgraditi cijelu listu sto je deset puta

vise nego potrebno. Na ovako malom primjeru to se i ne cini skupo no stvarna situ-

acija danasnjih web aplikacija je ta da koriste veliki broj kompleksnijih manipulacija

ogromnog DOM-a sto dovodi do drasticnog porasta broja nepotrebnih azuriranja.

React rjesava navedene probleme koristeci virtualan DOM na nacin da za svaki

DOM objekt u React-u postoji njegova virtualna reprezentacija, odnosno pojednos-

tavljena kopija.

Bazu virtualnog DOM-a cine React elementi, jednostavni objekti koji opisuju izgled

DOM-a. React komponente nemaju pristup virtualnom DOM-u pa se prije umetanja

u virtualan DOM trebaju pretvoriti u njih, ili sa

React.createElement(MyComponent);

ili ekvivalento pomocu JSX sintakse

<MyComponent />

Virtualan DOM ima ista svojstva kao i pravi DOM no nedostaje mu mogucnost di-

rektne promjene stanja na zaslonu. Taj nedostatak u ovom slucaju postaje prednost

jer cini manipulaciju pravim DOM-om mnogo brzom.

Page 30: ReactJS - zir.nsk.hr

28

6.1 Proces azuriranje DOM-a u React aplikacijama

Kronoloski slijed akcija

1. U React-u, na svaku promjenu nad podacima kreira se novi virtualan DOM.

To znaci da ce se virtualni DOM ponovno kreirati od nule na svaki poziv

funkcije setState() na nekoj od komponenti. Taj proces je jako brz i ne utjece

na performanse aplikacije.

2. U svakom trenutku, React rukuje dvjema instancama virtualnog DOM-a.

Jedna predstavlja azurirano stanje virtualnog DOM-a te druga njegovo pret-

hodno stanje. React koristi algoritam koji se naziva diff za usporedivanje

instanci virtualnog DOM-a u svrhu pronalazenja najmanjeg broja razlika sta-

nja prije i poslije azuriranja. Slozenost diff algoritma je linearna ili O(n) sto

znaci da ce njegova slozenost rasti proporcionalno velicini inputa u oznaci n.

3. Nakon sto je pomocu diff algoritma dobio podatak o promjenama koje su

nastale, React azurira samo te elemente na pravom DOM-a ne dirajuci ostale.

Nakon provedenih koraka React bi u primjeru liste bio dovoljno pametan da azurira

samo jedan izmijenjen zadatak s liste.

Uz to sto koristenje virtualnog DOM-a povecava porformanse azuriranja DOM-a,

nije potreban prevelik dodatan posao kada se azuriranje zeli postici. Naime, kao sto

je vec spomenuto, azuriranje virtualnog DOM-a ce se dogoditi na svaku promjenu

podataka, odnosno mjesta na kojima se oni drze a to je u React-u state objekt.

Page 31: ReactJS - zir.nsk.hr

29

7 React u praksi

Ovaj rad je popracen prakticnim dijelom, Planner aplikacijom ciji se kod moze

pronaci na linku:

https://github.com/lskalac/Diplomski-React-Asp.Net_WebApi.

7.1 O aplikaciji

Aplikacija predstavlja jednostavan planer za pracenje zadataka i dodavanja biljeski

koji sadrzi tri glavne stranice.

HomePage

HomePage je pocetna stranica koja sadrzi:

• Sekciju sa biljeskom koju je korisnik postavio kao aktivnu te link koji vodi na

stranicu na kojoj se ona moze promijeniti.

• Tablicu danasnjih zadataka koji se mogu oznaciti kao zavrseni.

Slika 2: Naslovna stranica

TaskPage

TaskPage je stranica koja sadrzi tri sekcije koje predstavljaju zadatke odvojene po

prioritetima. Korisnik moze dodati novi zadatak u svaku sekciju te postojeci oznaciti

kao zavrsen.

Page 32: ReactJS - zir.nsk.hr

30

Slika 3: Stranica zadataka

NotePage

NotePage je stranica koja sadrzi sve biljeske koje je korisnik unio. Korisnik moze

dodati novu, azurirati ili obrisati postojecu biljesku. Takoder, ovo je mjesto na kojem

korisnik moze oznaciti biljesku kao aktivnu kako bi ona bila vidljiva na naslovnoj

stranici.

Slika 4: Stranica biljezaka

Page 33: ReactJS - zir.nsk.hr

31

7.2 Koristene tehnologije i paketi

Planner je ReactJS aplikacija cija je server strana pisana u Asp.Net-u. Na klijentskoj

strani su koristene biblioteke, koje nisu spomenute u radu, kao sto su:

• axios - za stvaranje HTTP zahtjeva.

• bootstrap - za uredivanje elemenata DOM-a.

• rect-router - za navigaciju medu stranicama aplikacije.

• webpack - za grupiranja modula aplikacije.

7.3 Hijerarhija komponenti

Buduci da se React aplikacija sastoji od ugnjezdenih komponenti, bitno je dobro

postaviti relaciju medu njima. Iz tog razloga se prije prije pisanja koda preporuca

odvojiti vrijeme za crtanje osnovnog dijagrama komponenti. Dijagram komponenti

Planner aplikacije prikazan je na sljedecoj slici:

Slika 5: Dijagram komponenti aplikacije

Prateci kriterij prethodno spomenut o radu, koji govori o tome na kojem mjestu u

hijerahiji state objekt treba zivjeti, dodana je App komeponenta koja je zajednicka

komponenta HomePage, TaskPage i NotePage komponenti. Razlog tome je sto

Page 34: ReactJS - zir.nsk.hr

32

HomePage komponenta koristi podatke koji se koriste unuutar TaskPage i NotePage

komponente pa je state objekt, koji sadrzi zajednicke podatke, potrebno smjestiti

na razinu iznad njih, odnosno unutar App komponente.

7.4 Izrada podstabla NotePage

Ovo poglavlje pokazat ce kako izgleda podstablo s korijenom u komponenti NotePage

te kako se unutar njega izvode odredene akcije.

Kod NotePage komponente izgleda ovako:

import React from ’react’;

import PageTitle from ’../ common/PageTitle ’;

import NoteTable from ’../ note/NoteTable ’;

import NoteForm from ’../ note/NoteForm ’;

class NotePage extends React.Component {

render () {

return (

<div >

<PageTitle title="Notes" />

<div className="panel panel -default">

<div className="panel -heading">

<NoteForm onFormSubmit ={this.props.

onNoteFormSubmit} />

</div >

<div className="panel -body">

<NoteTable

notes={this.props.notes}

onDelete ={this.props.onNoteDelete}

onMark ={this.props.onNoteMark}

/>

</div >

</div >

</div >

);

}

}

export default NotePage;

U prve tri linije koda uvezeni su odredeni moduli o kojima ovisi ova komponenta,

React modul te tri komponente. Prva uvezena komponenta je PageTitle koja se

prosljeduju dva props parametra, title i subititle.

import React from ’react’;

Page 35: ReactJS - zir.nsk.hr

33

const PageTitle = (props) => {

return (

<div className="page -header">

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

</div >

);

};

export default PageTitle;

Unutar NotePage komponente, PageTitle komponenti je prop parametru title prosljeden

string ”Notes” pa ce renderirana komponenta na prikazu aplikacije jednostavno biti

element koji sadrzi rijec Notes.

Slika 6: Renderirana PageTitle komponenta

Sljedeca koristena komponenta je NoteTable komeponenta koja sluzi za ispisvanje

svih biljeski unutar tablice. Njezin kod izgleda ovako:

import React from ’react’;

import NoteTableRow from ’../ note/NoteTableRow ’;

class NoteTable extends React.Component {

render () {

const noteTableRows = this.props.notes.map((note) => (

<NoteTableRow

key={note.NoteId}

id={note.NoteId}

title={note.Title}

text={note.Text}

onDelete ={this.props.onDelete}

onMark ={this.props.onMark}

/>

));

return (

<div className="table -responsive">

<table className="table table -stripped table -hover">

<thead >

<tr >

<th className="col -lg -2"> Title </th >

<th className="col -lg -7"> Text </th >

Page 36: ReactJS - zir.nsk.hr

34

<th className="col -lg -3"> Action </th >

</tr >

</thead >

<tbody >

{noteTableRows}

</tbody >

</table >

</div >

);

}

}

export default NoteTable;

Buduci da tablica ne ispisuje jedan redak, redak tablice treba predstavljati kompo-

nentu. U tu svrhu je izradena NoteTableRow komponenta.

import React from ’react’;

class NoteTableRow extends React.Component{

constructor(props) {

super(props);

this.handleDelete = this.handleDelete.bind(this);

this.handleMark = this.handleMark.bind(this);

}

handleDelete () {

this.props.onDelete(this.props.id);

}

handleMark () {

this.props.onMark(this.props.id);

}

render () {

return (

<tr>

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

<td > {this.props.text} </td >

<td >

<button type="button" className="btn btn -default btn -sm m

-r-xs"> Edit </button >

<button type="button" className="btn btn -default btn -sm m

-r-xs" onClick ={this.handleMark}> Mark as active </

button >

<button type="button" className="btn btn -danger btn -sm"

onClick ={this.handleDelete}> Delete </button >

</td >

Page 37: ReactJS - zir.nsk.hr

35

</tr >

);

}

};

export default NoteTableRow;

Nakon njenog kreiranja, NoteTable komponenta ce moci renderirati bilo koji broj

NoteTableRow komponenti opisanih this.props.notes parametrom. Na ovaj nacin je

pokazano kako u React-u izvrsiti for each svojstvo koje se moze pronaci u drugim

frameworcima, primjerice u Angular-u ng-repeat.

Slika 7: Renderirana NoteTable komponenta

Na prethodnoj slici, svaki redak tablice zajedno s okidacima za akcije, cini jednu

NoteTableRow komponentu.

NotePage komponenta takoder sadrzi NoteForm komponentu koja sadrzi dugme za

otvaranje modala s formom za dodavanje nove ili editiranje postojece biljeske. Njen

kod izgleda ovako:

import React from ’react’;

class NoteForm extends React.Component {

constructor(props) {

super(props);

const title = this.props.title || "";

const text = this.props.text || "";

this.state = {

title: title ,

text: text

}

this.handleTitleChange = this.handleTitleChange.bind(this);

this.handleTextChange = this.handleTextChange.bind(this);

Page 38: ReactJS - zir.nsk.hr

36

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

}

handleTitleChange(e) {

this.setState ({ title: e.target.value });

}

handleTextChange(e) {

this.setState ({ text: e.target.value });

}

handleSubmit () {

this.props.onFormSubmit ({

NoteId: this.props.id ,

Title: this.state.title ,

Text: this.state.text

});

}

render () {

const modalTitle = this.props.id ? "Edit note" : "Insert note";

const buttonText = this.props.id ? "Edit" : "Add new";

const buttonClass = this.props.id ? "btn btn -default btn -sm" :

"btn btn -success";

return (

<div >

<div className="input -group col -lg -2" data -toggle="modal"

data -target="#noteModal">

<button className ={ buttonClass}> {buttonText} </button >

</div >

<div className="modal fade" id="noteModal" tabindex="-1" role="

dialog" aria -labelledby="myModalLabel" aria -hidden="true">

<div className="modal -dialog">

<div className="modal -content">

<div className="modal -header">

<button type="button" className="close" data -

dismiss="modal" aria -hidden="true">&times;</

button >

<h3 className="modal -title" id="myModalLabel"> {

modalTitle} </h3>

</div >

<div className="modal -body">

<form >

<div className="form -group">

<label for="title"> Title: </label >

<input type="text" className="form -control" id=

"title" maxlength="255"

value ={this.state.title} onChange ={this.

Page 39: ReactJS - zir.nsk.hr

37

handleTitleChange} />

</div >

<div className="form -group">

<label for="text"> Text: </label >

<textarea type="text" className="form -control"

id="text"

value ={this.state.text} onChange ={this.

handleTextChange} > </textarea >

</div >

</form >

</div >

<div className="modal -footer">

<button type="button" className="btn btn -default"

data -dismiss="modal">Close </button >

<button type="button" className="btn btn -primary"

onClick ={this.handleSubmit}>Save changes </

button >

</div >

</div >

</div >

</div >

</div >

);

}

}

export default NoteForm;

Renderirana NoteForm komponenta ce renderirati dugme koje sadrzi tekst Add new

te ce nakon njegovog pritiska renderirati formu za ispunjavanje svojstava biljeske.

Page 40: ReactJS - zir.nsk.hr

38

Slika 8: Renderirana NoteForm komponenta nakon pritiskanja dugmeta

Unutar NoteForm komponente korisnik moze pritisnuti dugme Save changes nakon

cega ce ocekivati da nova biljeska bude dodana u tablicu biljeski. Radi toga je unutar

App komponente definirana funkcija handleNoteFormSumit koja ce tu biljesku do-

dati na state objekt te je callback na nju poslan NoteForm komponenti pomocu prop

parametra onNoteFormSubmit. Taj prop parametar prosljeden je onClick dogadaju

dugmeta unutar NoteForm komponente pa ce ona njegovim pritiskom signalizirati

App komponenti da provede dodavanje biljeske na state objekt. App komponenta je

ujedno komponenta na kojoj se izvrsava sva logika nad podacima jer je ona vlasnik

state objekte. Njen kod izgleda ovako:

import React , { PropTypes } from ’react’;

import Header from ’./ common/Header ’;

import axios from ’axios’;

import Notifications , { notify } from ’react -notify -toast’;

class App extends React.Component {

constructor(props) {

super(props);

this.state = {

notes: [],

activeNote: {},

tasksByPriority: [],

todaysTasks: []

Page 41: ReactJS - zir.nsk.hr

39

};

this.handleNoteDelete = this.handleNoteDelete.bind(this);

this.handleNoteMark = this.handleNoteMark.bind(this);

this.handleNoteFormSumit = this.handleNoteFormSumit.bind(this);

this.handleTaskClose = this.handleTaskClose.bind(this);

this.handleTaskFormSubmit = this.handleTaskFormSubmit.bind(this

);

}

componentDidMount () {

axios.get(’http :// localhost :52975/ api/note’)

.then(( response) => {

let activeNote = response.data.find(function (note) {

return note.IsActive === true;

});

if (! activeNote)

activeNote = {

Title: "Decide. Commit. Succeed."

};

this.setState ({

notes: response.data ,

activeNote: activeNote

});

});

axios.get(’http :// localhost :52975/ api/task/priority ’)

.then(( response) => {

this.setState ({

tasksByPriority: response.data

});

});

axios.get(’http :// localhost :52975/ api/task/today ’)

.then(( response) => {

this.setState ({

todaysTasks: response.data

});

});

}

handleNoteDelete(noteId) {

axios.delete(’http :// localhost :52975/ api/note/’ + noteId)

.then(function (response) {

notify.show("Note removed successfully.", "success");

this.setState ({

notes: this.state.notes.filter(function (note) { return

note.NoteId !== noteId })

Page 42: ReactJS - zir.nsk.hr

40

});

}.bind(this))

.catch(function (error) {

notify.show("An error occurd.", "error");

});

}

handleNoteMark(noteId) {

axios.put(’http :// localhost :52975/ api/note/mark’, { NoteId:

noteId })

.then(function (response) {

notify.show("Note marked as active successfully.",

"success");

this.setState ({

activeNote: this.state.notes.find(function (

note) {

return note.NoteId === noteId;

})

});

}.bind(this))

.catch(function (error) {

notify.show("An error occurd.", "error");

});

}

handleNoteFormSumit(note) {

axios.post(’http :// localhost :52975/ api/note’, note)

.then(function (response) {

notify.show("Note inserted successfully.", "success");

note.NoteId = response.data;

this.setState ({

notes: this.state.notes.concat(note)

});

$(’#noteModal ’).modal(’hide’);}.bind(this))

.catch(function (error) {

notify.show("An error occurd.", "error");

});

}

handleTaskClose(taskId) {

axios.put(’http :// localhost :52975/ api/task/’ + taskId + ’/close ’

, {taskId : taskId })

.then(function (response) {

notify.show("Task closed successfully.", "success");

this.setState ({

tasksByPriority: this.state.tasksByPriority.map((task) =>

{

if (task.TaskId === taskId) {

Page 43: ReactJS - zir.nsk.hr

41

return Object.assign ({}, task , {

IsCompleted: true

});

} else {

return task;

}

})

});

}.bind(this))

.catch(function (error) {

notify.show("An error occurd.", "error");

});

}

handleTaskFormSubmit(task) {

axios.post(’http :// localhost :52975/ api/task’, task)

.then(function (response) {

notify.show("Task inserted successfully.", "success");

task.TaskId = response.data;

this.setState ({

tasksByPriority: this.state.tasksByPriority.concat(note)

});

$(’#taskModal ’).modal(’hide’);}.bind(this))

.catch(function (error) {

notify.show("An error occurd.", "error");

});

}

render () {

const children = React.Children.map(this.props.children , (child

) => {

return React.cloneElement(child , {

notes: this.state.notes ,

activeNote: this.state.activeNote ,

onNoteDelete: this.handleNoteDelete ,

onNoteMark: this.handleNoteMark ,

onNoteFormSubmit: this.handleNoteFormSumit ,

tasksByPriority: this.state.tasksByPriority ,

todaysTasks: this.state.todaysTasks ,

onTaskClose: this.handleTaskClose ,

onTaskFormSubmit: this.handleTaskFormSubmit

})

});

return (

<div >

<Notifications />

<Header />

<div className="container">

Page 44: ReactJS - zir.nsk.hr

42

{children}

</div >

</div >

);

}

}

App.propTypes = {

children: PropTypes.object.isRequired

};

export default App;

Page 45: ReactJS - zir.nsk.hr

43

Zavrsetak

Danas postoji mnogo JavaScript biblioteka koje uvelike olaksavaju posao u svijetu

izrade aplikacija. Naravno, svaka ima svoje prednosti i nedostatke kao sto je i u

slucaju framework-a pa se trazenje najboljih ne moze provesti generalno. Trazenje

najboljeg framework-a ili biblioteke ovisi o aplikaciji. Postavlja se pitanje koja su

svojstva framework-a ili biblioteke za nju jako bitna te koja se mogu zanemariti.

Osobno, na poslu jos uvijek radim s AngularJS-om 1 te nisam uocila da se rende-

riranja prikaza aplikacije dogadaju u nekom drasticno velikom vremenu. Mozda se

razlike vide tek na velikim podacima, kao sto ih Facebook ima.

Medutim, sto se tice praksa koje se koriste pri pisanju React komponenti mogu reci

da sam ih pomalo pocela primjenjivati u svom nacinu pisanja koda. Pokusavam

vecinu koda napisati genericki kako bi bio pogodan za ponovnu upotrebu. Podatke

ili funkcije koje su mi potrebne na vise mjesta u aplikaciji nastojim smjestiti na neku

zajednicku razinu u hijerarhiji sto i meni i ostalima uvelike olaksava snalazenje u

kodu.

Takoder, svida mi se sto je u React-u HTML i JavaScript kod u jednom dokumentu

pa se tako u procesu pisanja odredene funkcionalnosti ne treba snalaziti po vise

dokumenata odjednom.

Ako se pravilno koristi, React moze imati velike dobrobiti unutar aplikacije. Ovdje

se ne misli samo na brzinu i prostorni trosak vec i na prakse kojima uci sto za

rezultat moze dati kvalitetnu i brzu aplikaciju sastavljenu od ponovno upotrebljivih

cjelina unutar cijeg ce se koda svatko u buducnosti moci lako snaci i dodati neke

promjene.

Page 46: ReactJS - zir.nsk.hr

44

Literatura

[1] Anthony Accomazzo, Ari Lerner, Nate Murray, Clay Allsopp,

David Guttman, Tyler McGinnis, Fullstack React, The Complete Guide

to ReactJS and Friends, Fullstack.io, San Francisco, 2017

[2] https://facebook.github.io/react/

[3] https://www.codecademy.com/articles/react-virtual-dom

[4] http://www.hongkiat.com/blog/ecmascript-6/l

[5] http://reactkungfu.com/2015/10/the-difference-between-virtual-dom-and-dom/

[6] https://hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130

[7] https://codepen.io/somethingkindawierd/post/

es6-arrow-functions-this

[8] http://www.stefankrause.net/wp/?p=431

[9] https://app.pluralsight.com/library/courses/

react-redux-react-router-es6/table-of-contents

Page 47: ReactJS - zir.nsk.hr

45

Zivotopis

Rodena sam 22.01.1993. godine u Virovitici. 2007. godine zavrsila sam osnovnu

skolu u mjestu prebivalista Spisic Bukovici. Iste godine sam upisala Strukovnu

skolu u Virovitici, ekonomski smjer. Tijekom osnovne i srednje skole sudjelovala

sam na mnogim natjecanjima te skolskim i izvanskolskim aktivnostima. 2011. go-

dine na maturi sam odabrala matematicke i informaticke fakultete te iste godine

uspjesno upisala nastavnicki smjer matematike na Odjelu za matematiku Sveucilista

Josipa Jurja Strossmayera u Osijeku. Nakon nepunih tri godine odlucujem se pre-

baciti na preddiplomski smjer sa ciljem upisivanja diplomskog smjera Matematika

i racunarstvo. Te iste godine uspjesno zavrsavam preddiplomski studij uz zavrsni

rad Fermatov teorem beskonacnog spusta pod mentorstvom izv. prof. dr. sc. Ivana

Matica. S pocetkom sljedece akademske godine upisujem diplomski studij matema-

tike na smjeru Matematika i racunarstvo. U ljetu 2015. godine odradujem 2 mjeseca

prakse u Plavoj tvornici u Virovitici na poziciji frontend developera. U studenom

2016. godine pocinjem raditi u Osjeckoj software tvrtki Mono na poziciji software

developer.