React esittely

Front-end ohjelmoinnissa on tällä hetkellä kaksi suurta ja kaunista frameworkkia: AngularJS ja ReactJS. Angular on Googlen kehittämä framework ja ollut pidempään käytössä kuin React. React puolestaan on Facebookin alunperin kehittämä ja saavuttanut nopeasti suuren suosion julkaisunsa jälkeen. React on kehitetty suurien ja skaalautuvien web-palvelujen kehittämiseen.

Angularista on julkaistu vuonna 2016 uusi versio Angular 2, joka ei ole pelkästään uusi versio vaan kokonaan uudelleenkirjoitettu toteutus jossa myöskin kehittäjän kokema ohjelmointitapa on vaihtunut. Tämä onkin aiheuttanut joillekin Angular kehittäjille haasteita siirtymässä ja Angularin ”ykkösversio” on luonnollisesti edelleen laajasti käytössä koska siirtymä ei ole pelkkä versiopäivitys.

Netistä löytyy hyviä vertailuja Angularin ja Reactin ominaisuuksista ja siitä kumpi on ”parempi”. Kuten monissa monissa teknologiavalinnoissa, myös tässä kannattaa pohtia asiaa erilaisista näkökulmista ja tehdä valinta omien kriteerien pohjalta: kumpi tarjoaa sopivan mallin ja ominaisuudet juuri minun projektiini, kumpaa haluan oppia lisää, kumpi tulee jatkossa olemaan suositumpi, kumpaan löytyy helpommin kehittäjiä jne. Lopulta asiaan vaikuttaa järkisyiden lisäksi myös vahvasti kehittäjien kokema ohjelmointikokemus, selkeys, helppous, koodin rakenteen ymmärrettävyys jne. Molemmat ovat ehdottomasti tutustumisen arvoisia.

Tässä blogipostauksessa tutustumme tarkemmin Reactiin: tutustumme sen käyttämään ohjelmointimalliin sekä toteutamme yksinkertaisen HTML-sivun, jonka toiminnallisuus on toteutettu Reactilla.

Pohjatiedoksi voi vilkaista Wikipedian artikkelin Reactista. Omatoimiseen tutustumiseen ja kokeiluun suosittelen Reactin erittäin hyvää tutoriaalia.

Thinking in React

Reactin dokumentaatiossa esitellään mainiosti Reactin ajattelutapa: sivu voidaan jakaa komponentteihin jotka muodostavat sivulle hierarkkisen rakenteen. Komponenttiajattelussa lähdetään siitä että komponentti koostuu alikomponenteista jotka kukin toimivat tietyllä tapaa itsenäisesti mutta kuitenkin toisiinsa nojautuen. Komponenttiajattelun tuoman modulaarisuuden ansiosta komponentit voivat olla myös uudelleenkäytettäviä: samaa komponenttia voidaan kätevästi käyttää useassa eri paikassa.

React toiminnallisuuden toteutus lähteekin liikkeelle toiminnallisuuden komponenttijaosta: mietitään ensin miten toiminnalllisuus kannattaa jakaa osiin ja lähdetään sitten toteuttamaan näitä osiota.

Käyttöliittymän hahmottelu

Toteutamme tässä blogipostauksessa yksinkertaisen käyttöliittymän aiemmin esitellylle REST-palvelulle. Käyttöliittymä mahdollistaa uuden tietosisällön tallennuksen palveluun sekä olemassa olevan tiedon listauksen. Bonuksena toteutamme vielä kullekin tietoriville ”Poista” toiminnon, jolla data voidaan poistaa palvelusta.

Hahmotellaan ensin käyttöliitymä pikaisesti ”paperille”:

 

react_ui_draftSivulla on siis mahdollista tallentaa REST -palveluun JSON dataa. Kun data on tallennettu, se näkyy sivun alaosassa olevassa listauksessa. Listauksessa kunkin datan kohdalla on Poista -painike, jota painamalla data poistetaan palvelusta.

Hahmotellaan sivun toiminnallisuudelle React -komponenttijako:

 

react_ui_draft2

Punaisella merkitty osuus pitää sisällään kokonaisuuden, sen nimi olkoon RESTservice.

Tallennustoiminnallisuus on korostettu vihreällä, onkoon sen nimi vaikkapa AddData.

Olemassa olevan datan listauskomponentti on merkitty keltaisella ja se sisältää joukon ruskealla merkittyjä tietorivejä. Listan nimi voisi olla DataList ja yksittäisen rivin DataRow.

Toteutus

Aloitetaan toteutus toteuttamalla ensin osuus RESTService, joka ei vielä sisällä alikomponentteja. Samalla näemme kätevästi, mitä React -komponentti pitää minimissään sisällään.

Tehdään ensin HTML-sivu index.html. Sivulle ladataan käyttöön React-kirjasto käyttämällä source-tagia ja oma koodi ladataan tiedostosta restservice.js. Lisäksi ladataan käyttöön jQuery kirjasto AJAX-kutsua (=REST kutsu HTML-sivulta) varten, mikä ei kuitenkaan ole vaatimus Reactin puolesta.

HTML-sivulla itsessään ei siis ole mitään muuta kuin otsikkotiedot sekä yksi ainoa DIV-elementti, jonka tunniste on ”content”.

Lisätään HTML-tiedoston lisäksi tiedosto scripts/restservice.js:

Kooditiedostossa on toteutettuna varsin minimaalinen React-komponentti: sille on toteutettu ainoastaan Render -functio joka määrittää miten komponentti esitetään HTML -sivulla. Render-funtiossa käytetään ns. JSX -kuvauskieltä, joka poikkeaa hieman perus HTML -merkintäkielestä. React-komponentin Render -funktiossa on oleellista että komponentti koostuu yhdestä juurielementistä jonka alle kaikki komponenttiin kuuluvat HTML-elementit sijoitetaan. Tässä tapauksessa siis tehtiin yksi DIV -elementti ja sen alle hieman tekstiä.

Komponentti sijoitetaan sivulle kooditiedoston lopussa olevalla ReactDOM.render() kutsulla, jonka sisällä on määritetty että komponentti nimeltään RESTService sijoitetaan sivulla olevan content elementin sisälle. content elementtihän määritettiin HTML-sivulla jo aiemmin.

Kun kokeillaan avata selaimella sivu index.html, saadaan esille ensimmäinen Reactilla toteutettu sivu:

react_example1

Hyvä, tämähän oli helppoa! Tästä on hyvä jatkaa eteenpäin ja lisätä toiminnallisuutta RESTservice komponentin alaisuuteen.

Lisäämme seuraavaksi sivulle tiedon tallennukseen käytettävän komponentin joka on nimeltään AddData. Komponentti lisätään samaan tiedostoon kuin ensimmäinen komponentti eli restservice.js tiedosto näyttää jatkossa seuraavanlaiselta (lisätty osuus näkyy korostuksella):

Lomakkeen sisältävä komponentti on siis itsenäinen kokonaisuus joka on lisätty RESTservice komponentin sisälle rivillä 23.  Kun nyt tarkastellaan sivua selaimella, nähdään että molemmat komponentit näkyvät sivulla:

react_example2

Seuraavaksi lisätään lomakkeelle logiikka, joka käsittelee lomakkeen tietoja. Eli käytännössä kerää kirjoitetun tekstin talteen ja Tallenna -painikkeella lähettää sen REST -palveluun tallennettavaksi. Lisätään ensin komponentilla tilan käsittely eli määritetään React-komponentille tila, joka sisältää tässä tapauksessa syötettävän tekstin:

Tilan käsite on Reactin peruskivi. Kun oma ohjelmakoodi huolehtii komponentin tilan asettamisesta niin React huolehtii automaattisesti komponentin näyttämisen kulloisenkin tilatiedon perusteella. Tila alustetaan Reactin funtiossa getInitialState. Tämä funktio määrittelee samalla, millainen tilakäsite komponentilla on. Tässä tapauksessa tilassa on vain yksi tekstimuotoinen objekti joka alustetaan tyhjäksi. Aina kun käyttäjä muokkaa tekstikentän arvoa, päivitetään ohjelmakoodissa tilan arvoa vastaamaan syötettyä tekstiä. Tämä on ohjelmoijan vastuu datan sitomisesta. Seuraavan ohjelmalistauksen jälkeen käymme tarkemmin läpi datan sidontaa.

Lisätään seuraavaksi funktio lomakkeen tietojen lähettämiseen:

Yllä olevassa lisäyksessä lisättiin komponentille oma JavaScript funktio (handleSubmit) lomakkeen tietojen lähettämiseen ja kytkettiin se lomakkeen lähetyspainikkeeseen. AJAX kutsulla kutsutaan REST rajapinnassa olevaa tallennusta ja jos tallennus onnistuu niin näytetään viesti ”Tiedot tallennettu” ja tyhjennetään tilatiedoissa oleva inputText muuttuja (rivi 40). Kun kokeilemme tallennusta niin havaitsemme että tietojen tallennuksen jälkeen lomakkeella oleva tekstikenttää tyhjenee. Tämä on seurausta Reactin automaattisesta renderöinnistä: kun komponentin tila muuttuu, niin React huolehtii että tarvittavat komponentit renderöidään uudelleen.

Kuten huomaamme, Reactissa datan sidonta on niin sanotusti yksisuuntaista: tietojen lukeminen muuttujiin tehdään ohjelmakoodissa itse, mutta datan näyttäminen tilan mukaan tapahtuu automaattisesti. Tämä on Reactissa tietoinen valinta ja sillä pakotetaan ohjelmoija kiinnittämään huomio datan lukemiseen oikeasta paikasta. Esim. Angularissa datan sidonta on kaksisuuntaista.

Nyt meillä on siis ohjelmakoodi, jolla voidaan tallentaa dataa REST palveluun.

Toteutetaan loput sivun toiminnallisuudesta: lisätään syöttölomakkeen alapuolelle listauskomponentti, joka näyttää palveluun tallennetut tiedot allekkain. Listaus päivittyy aina kun uusi tieto on tallennettu palveluun. Kullakin listatulla datalla on myös Poista -painike, jolla kyseisen datan saa poistettua. Myös poiston jälkeen listaus päivittyy.

Lisätään sivulle kaksi uutta komponenttia: datojen listaamiseen tarkoitettu DataList joka sisältää DataRow komponentteja. DataRow ilmentää siis yhtä tallennettua dataa. Toteutamme datan lataamisen pääkomponentin alaisuuteen, josta sitä käytetään kolmessa tilanteessa: kun sivu latautuu, datan lisäämisen jälkeen ja datan poiston jälkeen.

Tarkastellaan yllä olevassa koodissa muutamaa kohtaa:

Ensinnäkin pääkomponentille (RESTService) on nyt lisätty funktiot getInitialState() joka alustaa komponentin tilan sekä componentDidMount() funtio joka lataa komponentin latautuessa datat REST palvelusta ja sijoittaa ne tilamuuttujaan. Lisäksi pääkomponenttiin on lisätty oma funktio onRemoveData(), joka tarjoaa datan poiston REST palvelupyynnöllä.

Riveillä 162 ja 163 näemme esimerkin, miten tietoa voidaan välittää komponenttien välillä. Komponentille voidaan antaa nimettyjä ”propseja” eli ”ominaisuuksia” (tai voisi kai niitä sanoa jopa komponentin argumenteiksi). Pääkomponentti siis välittää alikomponentille jotain tietoa, jota alikomponentti voi hyödyntää. Välitetty tieto voi olla konkreettista dataa mutta myös funktioviite. Rivillä 162 välitettävä onDataAdded -propsi on fuinktioviite. Rivillä 163 välitettävä datas puolestaan on taulukkomuotoinen objekti. Alikomponentissa tällaiseen nimettyyn propsiin viitataan nimellä, kuten rivillä 7. Itse asiassa rivillä 7 kyseinen funktioviite-propsi välitetään edelleen listakomponentilta eteenpäin kullekin DataRow komponentille. Tälla tapaa kukin rivi voi kutsua pääkomponenttiin määriteltyä funktiota kun Poista -painiketta painetaan.

Rivillä 80 taas AddData komponentti käyttää saamaansa funktioviitettä ja kutsuu funktiota kun on lisännyt dataa palveluun. Tällöin pääkomponentti lataa tiedot uusimmat tiedot REST palvelusta ja päivittää tilansa. Tästä seuraa että myös pääkomponentin alaisuudessa (ks. rivi 163) oleva listauskomponentti eli DataList päivittyy ”itsestään”, koska sille on välitetty tietoa tilamuuttujan kautta!

Riveillä 5-9 on mielenkiintoinen kohta. Siinä DataList komponentti looppaa omassa Render funktiossaan saamansa datarivit läpi ja muodostaa niiden pohjalta joukon DataRow komponentteja. Render funktion return -osuudesta näemme, että muodostettu joukko voidaan renderöidä kästevästi suoraan tästä muuttujasta (rivi 14).

Toteutuksemme on nyt valmis! Jotta voimme kokeilla sitä käytännössä, käynnistämme ensin REST-blogipostauksessa esitellyn yksinkertaisen REST palvelun.

Sitten avataan selaimella index.html ja kokeillaan toiminnallisuutta.

Tallennetaan uusi JSON data ja todetaan että listaus todellakin päivittyy kun uusi JSON-data on tallennettu:

react_example3

 

react_example_test2

Lisätään vielä toinenkin data ja nähdään että se tulee listaukseen mukaan:

react_example_test3

Kokeillaan poistoa ja painetaan ylemmän tietoalkion alapuolelta Poista. Kun poisto on tehty, listaus päivittyy ja listalla on enään yksi alkio:

react_example_test4

Yhteenveto

Tässä blogipostauksessa tutustuimme Reactin ajattelutapaan ja käsitteisiin sekä kokeilimme React -ohjelmointia käytännössä. Kuten esimerkkimme kautta opimme, React tarjoaa varsin selkeän tavan web-sovelluksen rakenteen määrittämiseen. Reactin ”learnin curve” eli oppimiskäyrä on varsin loiva eli simppelin React -toteutuksen tekeminen ja ymmärtäminen on varsin helppoa. Yksisuuntainen datan sidonta pakottaa ohjelmoijan käsittelemään syötteen itsenäisesti mutta renderöinti sitä vastoin tapahtuu automaattisesti.

Yhteenvetona voisimme sanoa, että Reactilla on varsin miellyttävää toteuttaa Front-end -logiikkaa ja alkuun pääsee nopeasti ja helposti.

Lisätietoa Reactista löydät Reactin dokumentaatiosta.