{"id":363,"date":"2016-09-18T18:01:31","date_gmt":"2016-09-18T16:01:31","guid":{"rendered":"http:\/\/localhost:8888\/wordpress\/?p=363"},"modified":"2017-01-20T08:34:40","modified_gmt":"2017-01-20T06:34:40","slug":"react-esittely","status":"publish","type":"post","link":"https:\/\/www.pilvikoodari.net\/?p=363","title":{"rendered":"React esittely"},"content":{"rendered":"<p>Front-end ohjelmoinnissa on t\u00e4ll\u00e4 hetkell\u00e4 kaksi suurta ja kaunista frameworkkia: <a href=\"https:\/\/angularjs.org\/\" target=\"_blank\">AngularJS <\/a>ja <a href=\"https:\/\/facebook.github.io\/react\/\" target=\"_blank\">ReactJS<\/a>. Angular on Googlen kehitt\u00e4m\u00e4 framework ja ollut pidemp\u00e4\u00e4n k\u00e4yt\u00f6ss\u00e4 kuin React. React puolestaan on Facebookin alunperin kehitt\u00e4m\u00e4 ja saavuttanut nopeasti suuren suosion julkaisunsa j\u00e4lkeen. React on kehitetty suurien ja skaalautuvien web-palvelujen kehitt\u00e4miseen.<\/p>\n<p>Angularista on julkaistu vuonna 2016 uusi versio Angular 2, joka ei ole pelk\u00e4st\u00e4\u00e4n uusi versio vaan kokonaan uudelleenkirjoitettu toteutus jossa my\u00f6skin kehitt\u00e4j\u00e4n kokema ohjelmointitapa on vaihtunut. T\u00e4m\u00e4 onkin aiheuttanut joillekin Angular kehitt\u00e4jille haasteita siirtym\u00e4ss\u00e4 ja Angularin &#8221;ykk\u00f6sversio&#8221; on luonnollisesti edelleen laajasti k\u00e4yt\u00f6ss\u00e4 koska siirtym\u00e4 ei ole pelkk\u00e4 versiop\u00e4ivitys.<\/p>\n<p>Netist\u00e4 l\u00f6ytyy hyvi\u00e4 <a href=\"http:\/\/tutorials.pluralsight.com\/front-end-javascript\/angular-vs-react-a-side-by-side-comparison\" target=\"_blank\">vertailuja<\/a> Angularin ja Reactin ominaisuuksista ja siit\u00e4 kumpi on &#8221;parempi&#8221;. Kuten monissa monissa teknologiavalinnoissa, my\u00f6s t\u00e4ss\u00e4 kannattaa pohtia asiaa erilaisista n\u00e4k\u00f6kulmista ja tehd\u00e4 valinta omien kriteerien pohjalta: kumpi tarjoaa sopivan mallin ja ominaisuudet juuri minun projektiini, kumpaa haluan oppia lis\u00e4\u00e4, kumpi tulee jatkossa olemaan suositumpi, kumpaan l\u00f6ytyy helpommin kehitt\u00e4ji\u00e4 jne. Lopulta asiaan vaikuttaa j\u00e4rkisyiden lis\u00e4ksi my\u00f6s vahvasti kehitt\u00e4jien kokema ohjelmointikokemus, selkeys, helppous, koodin rakenteen ymm\u00e4rrett\u00e4vyys jne. Molemmat ovat ehdottomasti tutustumisen arvoisia.<\/p>\n<p>T\u00e4ss\u00e4 blogipostauksessa tutustumme tarkemmin Reactiin: tutustumme sen k\u00e4ytt\u00e4m\u00e4\u00e4n ohjelmointimalliin sek\u00e4 toteutamme yksinkertaisen HTML-sivun, jonka toiminnallisuus on toteutettu Reactilla.<\/p>\n<p>Pohjatiedoksi voi vilkaista <a href=\"https:\/\/en.wikipedia.org\/wiki\/React_(JavaScript_library)\" target=\"_blank\">Wikipedian artikkelin<\/a> Reactista. Omatoimiseen tutustumiseen ja kokeiluun suosittelen Reactin eritt\u00e4in hyv\u00e4\u00e4 <a href=\"https:\/\/facebook.github.io\/react\/docs\/tutorial.html\" target=\"_blank\">tutoriaalia<\/a>.<\/p>\n<p><strong>Thinking in React<\/strong><\/p>\n<p>Reactin dokumentaatiossa <a href=\"https:\/\/facebook.github.io\/react\/docs\/thinking-in-react.html\" target=\"_blank\">esitell\u00e4\u00e4n <\/a>mainiosti Reactin ajattelutapa: sivu voidaan jakaa komponentteihin jotka muodostavat sivulle hierarkkisen rakenteen. Komponenttiajattelussa l\u00e4hdet\u00e4\u00e4n siit\u00e4 ett\u00e4 komponentti koostuu alikomponenteista jotka kukin toimivat tietyll\u00e4 tapaa itsen\u00e4isesti mutta kuitenkin toisiinsa nojautuen. Komponenttiajattelun tuoman modulaarisuuden ansiosta komponentit voivat olla my\u00f6s uudelleenk\u00e4ytett\u00e4vi\u00e4: samaa komponenttia voidaan k\u00e4tev\u00e4sti k\u00e4ytt\u00e4\u00e4 useassa eri paikassa.<\/p>\n<p>React toiminnallisuuden toteutus l\u00e4hteekin liikkeelle toiminnallisuuden komponenttijaosta: mietit\u00e4\u00e4n ensin miten toiminnalllisuus kannattaa jakaa osiin ja l\u00e4hdet\u00e4\u00e4n sitten toteuttamaan n\u00e4it\u00e4 osiota.<\/p>\n<p><strong>K\u00e4ytt\u00f6liittym\u00e4n hahmottelu<\/strong><\/p>\n<p>Toteutamme t\u00e4ss\u00e4 blogipostauksessa yksinkertaisen k\u00e4ytt\u00f6liittym\u00e4n <a href=\"https:\/\/www.pilvikoodari.net\/?p=218\" target=\"_blank\">aiemmin esitellylle REST-palvelulle<\/a>. K\u00e4ytt\u00f6liittym\u00e4 mahdollistaa uuden tietosis\u00e4ll\u00f6n tallennuksen palveluun sek\u00e4 olemassa olevan tiedon listauksen. Bonuksena toteutamme viel\u00e4 kullekin tietoriville &#8221;Poista&#8221; toiminnon, jolla data voidaan poistaa palvelusta.<\/p>\n<p>Hahmotellaan ensin k\u00e4ytt\u00f6liitym\u00e4 pikaisesti &#8221;paperille&#8221;:<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft.jpg\" rel=\"attachment wp-att-369\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-369 size-full\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft.jpg\" alt=\"react_ui_draft\" width=\"732\" height=\"686\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft.jpg 732w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft-300x281.jpg 300w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a>Sivulla on siis mahdollista tallentaa REST -palveluun JSON dataa. Kun data on tallennettu, se n\u00e4kyy sivun alaosassa olevassa listauksessa. Listauksessa kunkin datan kohdalla on Poista -painike, jota painamalla data poistetaan palvelusta.<\/p>\n<p>Hahmotellaan sivun toiminnallisuudelle React -komponenttijako:<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft2.jpg\" rel=\"attachment wp-att-371\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-371\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft2.jpg\" alt=\"react_ui_draft2\" width=\"732\" height=\"686\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft2.jpg 732w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/React_ui_draft2-300x281.jpg 300w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><\/p>\n<p>Punaisella merkitty osuus pit\u00e4\u00e4 sis\u00e4ll\u00e4\u00e4n kokonaisuuden, sen nimi olkoon <strong>RESTservice<\/strong>.<\/p>\n<p>Tallennustoiminnallisuus on korostettu vihre\u00e4ll\u00e4, onkoon sen nimi vaikkapa <strong>AddData<\/strong>.<\/p>\n<p>Olemassa olevan datan listauskomponentti on merkitty keltaisella ja se sis\u00e4lt\u00e4\u00e4 joukon ruskealla merkittyj\u00e4 tietorivej\u00e4. Listan nimi voisi olla <strong>DataList <\/strong>ja yksitt\u00e4isen rivin <strong>DataRow<\/strong>.<\/p>\n<p><strong>Toteutus<\/strong><\/p>\n<p>Aloitetaan toteutus toteuttamalla ensin osuus <strong>RESTService,<\/strong> joka ei viel\u00e4 sis\u00e4ll\u00e4 alikomponentteja. Samalla n\u00e4emme k\u00e4tev\u00e4sti, mit\u00e4 React -komponentti pit\u00e4\u00e4 minimiss\u00e4\u00e4n sis\u00e4ll\u00e4\u00e4n.<\/p>\n<p>Tehd\u00e4\u00e4n ensin HTML-sivu index.html. Sivulle ladataan k\u00e4ytt\u00f6\u00f6n React-kirjasto k\u00e4ytt\u00e4m\u00e4ll\u00e4 source-tagia ja oma koodi ladataan tiedostosta restservice.js. Lis\u00e4ksi ladataan k\u00e4ytt\u00f6\u00f6n jQuery kirjasto AJAX-kutsua (=REST kutsu HTML-sivulta) varten, mik\u00e4 ei kuitenkaan ole vaatimus Reactin puolesta.<\/p>\n<pre class=\"lang:default decode:true \" title=\"index.html\">&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n  &lt;head&gt;\r\n    &lt;meta charset=\"utf-8\" \/&gt;\r\n    &lt;title&gt;REST palvelun testisivu&lt;\/title&gt;\r\n    &lt;script src=\"https:\/\/unpkg.com\/react@15.3.1\/dist\/react.js\"&gt;&lt;\/script&gt;\r\n    &lt;script src=\"https:\/\/unpkg.com\/react-dom@15.3.1\/dist\/react-dom.js\"&gt;&lt;\/script&gt;\r\n    &lt;script src=\"https:\/\/unpkg.com\/babel-core@5.8.38\/browser.min.js\"&gt;&lt;\/script&gt;\r\n    &lt;script src=\"https:\/\/unpkg.com\/jquery@3.1.0\/dist\/jquery.min.js\"&gt;&lt;\/script&gt;\r\n  &lt;\/head&gt;\r\n  &lt;body&gt;\r\n    &lt;script type=\"text\/babel\" src=\"scripts\/restservice.js\"&gt;&lt;\/script&gt;\r\n    &lt;div id=\"content\"&gt;&lt;\/div&gt;\r\n  &lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>HTML-sivulla itsess\u00e4\u00e4n ei siis ole mit\u00e4\u00e4n muuta kuin otsikkotiedot sek\u00e4 yksi ainoa DIV-elementti, jonka tunniste on &#8221;content&#8221;.<\/p>\n<p>Lis\u00e4t\u00e4\u00e4n HTML-tiedoston lis\u00e4ksi tiedosto scripts\/restservice.js:<\/p>\n<pre class=\"lang:js decode:true\" title=\"restservice.js\">var RESTservice = React.createClass({\r\n\r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"RESTservice\"&gt;\r\n        Hello, I am a React component.\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nReactDOM.render(\r\n  &lt;RESTservice \/&gt;,\r\n  document.getElementById('content')\r\n);\r\n<\/pre>\n<p>Kooditiedostossa on toteutettuna varsin minimaalinen React-komponentti: sille on toteutettu ainoastaan Render -functio joka m\u00e4\u00e4ritt\u00e4\u00e4 miten komponentti esitet\u00e4\u00e4n HTML -sivulla. Render-funtiossa k\u00e4ytet\u00e4\u00e4n ns. JSX -kuvauskielt\u00e4, joka poikkeaa hieman perus HTML -merkint\u00e4kielest\u00e4. React-komponentin Render -funktiossa on oleellista ett\u00e4 komponentti koostuu yhdest\u00e4 juurielementist\u00e4 jonka alle kaikki komponenttiin kuuluvat HTML-elementit sijoitetaan. T\u00e4ss\u00e4 tapauksessa siis tehtiin yksi DIV -elementti ja sen alle hieman teksti\u00e4.<\/p>\n<p>Komponentti sijoitetaan sivulle kooditiedoston lopussa olevalla ReactDOM.render() kutsulla, jonka sis\u00e4ll\u00e4 on m\u00e4\u00e4ritetty ett\u00e4 komponentti nimelt\u00e4\u00e4n <strong>RESTService <\/strong>sijoitetaan sivulla olevan <strong>content <\/strong>elementin sis\u00e4lle. <strong>content<\/strong> elementtih\u00e4n m\u00e4\u00e4ritettiin HTML-sivulla jo aiemmin.<\/p>\n<p>Kun kokeillaan avata selaimella sivu index.html, saadaan esille ensimm\u00e4inen Reactilla toteutettu sivu:<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example1.jpg\" rel=\"attachment wp-att-381\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-381\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example1.jpg\" alt=\"react_example1\" width=\"583\" height=\"334\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example1.jpg 583w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example1-300x172.jpg 300w\" sizes=\"auto, (max-width: 583px) 100vw, 583px\" \/><\/a><\/p>\n<p>Hyv\u00e4, t\u00e4m\u00e4h\u00e4n oli helppoa! T\u00e4st\u00e4 on hyv\u00e4 jatkaa eteenp\u00e4in ja lis\u00e4t\u00e4 toiminnallisuutta <strong>RESTservice<\/strong> komponentin alaisuuteen.<\/p>\n<p>Lis\u00e4\u00e4mme seuraavaksi sivulle tiedon tallennukseen k\u00e4ytett\u00e4v\u00e4n komponentin joka on nimelt\u00e4\u00e4n <strong>AddData.<\/strong> Komponentti lis\u00e4t\u00e4\u00e4n samaan tiedostoon kuin ensimm\u00e4inen komponentti eli restservice.js tiedosto n\u00e4ytt\u00e4\u00e4 jatkossa seuraavanlaiselta (lis\u00e4tty osuus n\u00e4kyy korostuksella):<\/p>\n<pre class=\"lang:default mark:1-16,23 decode:true\" title=\"restservice.js\">var AddData = React.createClass({\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"AddData\"&gt;\r\n        &lt;form&gt;\r\n        &lt;textarea rows=\"5\" cols=\"40\" placeholder=\"Sy\u00f6t\u00e4 tallennettava data...\" \/&gt;\r\n        &lt;br\/&gt;\r\n        &lt;input type=\"submit\" value=\"Tallenna\" \/&gt;\r\n      &lt;\/form&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nvar RESTservice = React.createClass({\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"RESTservice\"&gt;\r\n        Hello, I am a React component.\r\n        &lt;AddData \/&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n  \r\n});\r\n\r\nReactDOM.render(\r\n  &lt;RESTservice \/&gt;,\r\n  document.getElementById('content')\r\n);\r\n<\/pre>\n<p>Lomakkeen sis\u00e4lt\u00e4v\u00e4 komponentti on siis itsen\u00e4inen kokonaisuus joka on lis\u00e4tty <strong>RESTservice <\/strong>komponentin sis\u00e4lle rivill\u00e4 23.<strong>\u00a0 <\/strong>Kun nyt tarkastellaan sivua selaimella, n\u00e4hd\u00e4\u00e4n ett\u00e4 molemmat komponentit n\u00e4kyv\u00e4t sivulla:<strong><br \/>\n<\/strong><\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example2.jpg\" rel=\"attachment wp-att-386\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-386\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example2.jpg\" alt=\"react_example2\" width=\"582\" height=\"388\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example2.jpg 582w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example2-300x200.jpg 300w\" sizes=\"auto, (max-width: 582px) 100vw, 582px\" \/><\/a><\/p>\n<p>Seuraavaksi lis\u00e4t\u00e4\u00e4n lomakkeelle logiikka, joka k\u00e4sittelee lomakkeen tietoja. Eli k\u00e4yt\u00e4nn\u00f6ss\u00e4 ker\u00e4\u00e4 kirjoitetun tekstin talteen ja Tallenna -painikkeella l\u00e4hett\u00e4\u00e4 sen REST -palveluun tallennettavaksi. Lis\u00e4t\u00e4\u00e4n ensin komponentilla <strong>tilan k\u00e4sittely<\/strong> eli m\u00e4\u00e4ritet\u00e4\u00e4n React-komponentille tila, joka sis\u00e4lt\u00e4\u00e4 t\u00e4ss\u00e4 tapauksessa sy\u00f6tett\u00e4v\u00e4n tekstin:<\/p>\n<pre class=\"lang:js mark:3-11,19-20 decode:true\" title=\"restservice.js\">var AddData = React.createClass({\r\n\r\n  getInitialState: function() {\r\n    return {\r\n        inputText : ''\r\n    };\r\n  },\r\n\r\n  handleInputChange : function(e) {\r\n    this.setState( { inputText : e.target.value});\r\n  },\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"AddData\"&gt;\r\n        &lt;form&gt;\r\n        &lt;textarea rows=\"5\" cols=\"40\" placeholder=\"Sy\u00f6t\u00e4 tallennettava data...\" \r\n          value={this.state.inputText}\r\n          onChange={this.handleInputChange}\/&gt;\r\n        &lt;br\/&gt;\r\n        &lt;input type=\"submit\" value=\"Tallenna\" \/&gt;\r\n      &lt;\/form&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nvar RESTservice = React.createClass({\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"RESTservice\"&gt;\r\n        Hello, I am a React component.\r\n        &lt;AddData \/&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nReactDOM.render(\r\n  &lt;RESTservice \/&gt;,\r\n  document.getElementById('content')\r\n);\r\n<\/pre>\n<p><strong>Tilan k\u00e4site on Reactin peruskivi.<\/strong> Kun oma ohjelmakoodi huolehtii komponentin tilan asettamisesta niin React huolehtii automaattisesti komponentin n\u00e4ytt\u00e4misen kulloisenkin tilatiedon perusteella. Tila alustetaan Reactin funtiossa <strong>getInitialState.<\/strong> T\u00e4m\u00e4 funktio m\u00e4\u00e4rittelee samalla, millainen tilak\u00e4site komponentilla on. T\u00e4ss\u00e4 tapauksessa tilassa on vain yksi tekstimuotoinen objekti joka alustetaan tyhj\u00e4ksi. Aina kun k\u00e4ytt\u00e4j\u00e4 muokkaa tekstikent\u00e4n arvoa, p\u00e4ivitet\u00e4\u00e4n ohjelmakoodissa tilan arvoa vastaamaan sy\u00f6tetty\u00e4 teksti\u00e4. T\u00e4m\u00e4 on ohjelmoijan vastuu datan sitomisesta. Seuraavan ohjelmalistauksen j\u00e4lkeen k\u00e4ymme tarkemmin l\u00e4pi datan sidontaa.<\/p>\n<p>Lis\u00e4t\u00e4\u00e4n seuraavaksi funktio lomakkeen tietojen l\u00e4hett\u00e4miseen:<\/p>\n<pre class=\"lang:js mark:13-47,54 decode:true\" title=\"restservice.js\">var AddData = React.createClass({\r\n\r\n  getInitialState: function() {\r\n    return {\r\n        inputText : ''\r\n    };\r\n  },\r\n\r\n  handleInputChange : function(e) {\r\n    this.setState( { inputText : e.target.value});\r\n  },\r\n\r\n  handleSubmit: function(e) {\r\n    e.preventDefault();\r\n    var text = this.state.inputText.trim();\r\n    if (!text) {\r\n      alert(\"Anna data.\");\r\n      return;\r\n    }\r\n\r\n    var dataToSave;\r\n    try {\r\n        dataToSave = JSON.parse(this.state.inputText.trim());\r\n    } catch(e) {\r\n        alert(\"Virheellinen data.\");\r\n        return;\r\n    }\r\n\r\n    \/\/ Send form data to REST service using AJAX:\r\n    $.ajax({\r\n        url : 'http:\/\/localhost:8080\/items\/',\r\n        type: 'POST',\r\n        dataType: 'json',\r\n        cache: false,\r\n        timeout: 15000,\r\n        data: JSON.stringify(dataToSave),\r\n\r\n        success: function(data) {\r\n            alert(\"Tiedot tallennettu.\");\r\n            this.setState({inputText: ''});\r\n        }.bind(this),\r\n\r\n        error: function(xhr, status, err) {\r\n            alert(\"Tallennus ep\u00e4onnistui.\");\r\n        }.bind(this)\r\n\r\n    });\/\/ajax              \r\n\r\n  },\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"AddData\"&gt;\r\n        &lt;form onSubmit={this.handleSubmit}&gt;\r\n        &lt;textarea rows=\"5\" cols=\"40\" placeholder=\"Sy\u00f6t\u00e4 tallennettava data...\" \r\n          value={this.state.inputText}\r\n          onChange={this.handleInputChange}\/&gt;\r\n        &lt;br\/&gt;\r\n        &lt;input type=\"submit\" value=\"Tallenna\" \/&gt;\r\n      &lt;\/form&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nvar RESTservice = React.createClass({\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"RESTservice\"&gt;\r\n        Hello, I am a React component.\r\n        &lt;AddData \/&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nReactDOM.render(\r\n  &lt;RESTservice \/&gt;,\r\n  document.getElementById('content')\r\n);\r\n<\/pre>\n<p>Yll\u00e4 olevassa lis\u00e4yksess\u00e4 <strong>lis\u00e4ttiin komponentille oma JavaScript funktio<\/strong> (handleSubmit) lomakkeen tietojen l\u00e4hett\u00e4miseen ja kytkettiin se lomakkeen l\u00e4hetyspainikkeeseen. AJAX kutsulla kutsutaan REST rajapinnassa olevaa tallennusta ja jos tallennus onnistuu niin n\u00e4ytet\u00e4\u00e4n viesti &#8221;Tiedot tallennettu&#8221; ja tyhjennet\u00e4\u00e4n tilatiedoissa oleva <strong>inputText<\/strong> muuttuja (rivi 40). Kun kokeilemme tallennusta niin havaitsemme ett\u00e4 tietojen tallennuksen j\u00e4lkeen lomakkeella oleva tekstikentt\u00e4\u00e4 tyhjenee. T\u00e4m\u00e4 on seurausta Reactin automaattisesta render\u00f6innist\u00e4: kun komponentin <strong>tila<\/strong> muuttuu, niin React huolehtii ett\u00e4 tarvittavat komponentit render\u00f6id\u00e4\u00e4n uudelleen.<\/p>\n<p>Kuten huomaamme, Reactissa <strong>datan sidonta<\/strong> on niin sanotusti <strong>yksisuuntaista<\/strong>: tietojen lukeminen muuttujiin tehd\u00e4\u00e4n ohjelmakoodissa itse, mutta datan n\u00e4ytt\u00e4minen tilan mukaan tapahtuu automaattisesti. T\u00e4m\u00e4 on Reactissa tietoinen valinta ja sill\u00e4 pakotetaan ohjelmoija kiinnitt\u00e4m\u00e4\u00e4n huomio datan lukemiseen oikeasta paikasta. Esim. Angularissa datan sidonta on kaksisuuntaista.<\/p>\n<p>Nyt meill\u00e4 on siis ohjelmakoodi, jolla voidaan tallentaa dataa REST palveluun.<\/p>\n<p>Toteutetaan loput sivun toiminnallisuudesta: lis\u00e4t\u00e4\u00e4n sy\u00f6tt\u00f6lomakkeen alapuolelle listauskomponentti, joka n\u00e4ytt\u00e4\u00e4 palveluun tallennetut tiedot allekkain. Listaus p\u00e4ivittyy aina kun uusi tieto on tallennettu palveluun. Kullakin listatulla datalla on my\u00f6s <em>Poista<\/em> -painike, jolla kyseisen datan saa poistettua. My\u00f6s poiston j\u00e4lkeen listaus p\u00e4ivittyy.<\/p>\n<p>Lis\u00e4t\u00e4\u00e4n sivulle kaksi uutta komponenttia: datojen listaamiseen tarkoitettu <strong>DataList<\/strong> joka sis\u00e4lt\u00e4\u00e4 <strong>DataRow <\/strong>komponentteja. <strong>DataRow<\/strong> ilment\u00e4\u00e4 siis yht\u00e4 tallennettua dataa. Toteutamme datan lataamisen p\u00e4\u00e4komponentin alaisuuteen, josta sit\u00e4 k\u00e4ytet\u00e4\u00e4n kolmessa tilanteessa: kun sivu latautuu, datan lis\u00e4\u00e4misen j\u00e4lkeen ja datan poiston j\u00e4lkeen.<\/p>\n<pre class=\"lang:js mark:1-39,80,110-156,162-163 decode:true\" title=\"restservice.js\">var DataList = React.createClass({\r\n\r\n  render: function() {\r\n    \r\n    var rows = this.props.datas.map(function(data) {\r\n            return (\r\n                &lt;DataRow key={data.id} data={data} onRemoveData={this.props.onRemoveData} \/&gt;\r\n            )\r\n        }, this);\r\n\r\n    return (\r\n            &lt;div className=\"DataList\"&gt;\r\n            &lt;h2&gt;Tallennetut&lt;\/h2&gt;\r\n                {rows}\r\n            &lt;\/div&gt;\r\n        );\r\n  }\r\n});\r\n\r\nvar DataRow = React.createClass({\r\n\r\n  remove(id) {\r\n    if(confirm('Poistetaanko data?'))\r\n      this.props.onRemoveData(id);\r\n  },\r\n\r\n  render: function() {\r\n    return (\r\n        &lt;div className=\"DataRow\"&gt;\r\n            &lt;hr\/&gt;\r\n            &lt;textarea disabled=\"true\" rows=\"5\" cols=\"40\" \r\n            value={ JSON.stringify(this.props.data) } \/&gt;\r\n            &lt;br\/&gt;\r\n            &lt;button type=\"button\" onClick={this.remove.bind(this,this.props.data.id)}&gt;Poista&lt;\/button&gt;\r\n        &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nvar AddData = React.createClass({\r\n\r\n  getInitialState: function() {\r\n    return {\r\n        inputText : ''\r\n    };\r\n  },\r\n\r\n  handleInputChange : function(e) {\r\n    this.setState( { inputText : e.target.value});\r\n  },\r\n\r\n  handleSubmit: function(e) {\r\n    e.preventDefault();\r\n    var text = this.state.inputText.trim();\r\n    if (!text) {\r\n      alert(\"Anna data.\");\r\n      return;\r\n    }\r\n\r\n    var dataToSave;\r\n    try {\r\n        dataToSave = JSON.parse(this.state.inputText.trim());\r\n    } catch(e) {\r\n        alert(\"Virheellinen data.\");\r\n        return;\r\n    }\r\n\r\n    \/\/ Send form data to REST service using AJAX:\r\n    $.ajax({\r\n        url : 'http:\/\/localhost:8080\/items\/',\r\n        type: 'POST',\r\n        dataType: 'json',\r\n        cache: false,\r\n        timeout: 15000,\r\n        data:  dataToSave,\r\n\r\n        success: function(data) {\r\n            this.setState({inputText: ''});\r\n            this.props.onDataAdded();\r\n        }.bind(this),\r\n\r\n        error: function(xhr, status, err) {\r\n            alert(\"Tallennus ep\u00e4onnistui.\");\r\n        }.bind(this)\r\n\r\n    });\/\/ajax              \r\n\r\n  },\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"AddData\"&gt;\r\n        &lt;h2&gt;Tallenna uusi&lt;\/h2&gt;\r\n        &lt;form onSubmit={this.handleSubmit}&gt;\r\n        &lt;textarea rows=\"5\" cols=\"40\" placeholder=\"Sy\u00f6t\u00e4 tallennettava data...\" \r\n          value={this.state.inputText}\r\n          onChange={this.handleInputChange}\/&gt;\r\n        &lt;br\/&gt;\r\n        &lt;input type=\"submit\" value=\"Tallenna\" \/&gt;\r\n      &lt;\/form&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nvar RESTservice = React.createClass({\r\n\r\n  getInitialState: function() {\r\n    return {\r\n        datas : [] \r\n    };\r\n  },\r\n\r\n  loadDatas : function() {\r\n    \/\/ load data from REST service using AJAX:\r\n    $.ajax({\r\n        url : 'http:\/\/localhost:8080\/items\/',\r\n        type: 'GET',\r\n        dataType: 'json',\r\n        cache: false,\r\n        timeout: 15000,\r\n\r\n        success: function(data) {\r\n            this.setState({datas: data});\r\n        }.bind(this),\r\n\r\n        error: function(xhr, status, err) {\r\n            alert('Tietojen haku ep\u00e4onnistui.');\r\n        }.bind(this)\r\n    });\/\/ajax \r\n  },\r\n\r\n  componentDidMount: function() {\r\n    this.loadDatas();\r\n  },\r\n\r\n  onRemoveData : function(id) {\r\n    \/\/ call DELETE method from REST service using AJAX:\r\n    $.ajax({\r\n        url : 'http:\/\/localhost:8080\/items\/' + id,\r\n        type: 'DELETE',\r\n        dataType: 'json',\r\n        cache: false,\r\n        timeout: 15000,\r\n\r\n        success: function(data) {\r\n            this.loadDatas();\r\n        }.bind(this),\r\n\r\n        error: function(xhr, status, err) {\r\n            alert('Tietojen poisto ep\u00e4onnistui.');\r\n        }.bind(this)\r\n    });\/\/ajax \r\n },\r\n  \r\n  render: function() {\r\n    return (\r\n      &lt;div className=\"RESTservice\"&gt;\r\n        Hello, I am a React component.\r\n        &lt;AddData onDataAdded = {this.loadDatas} \/&gt;\r\n        &lt;DataList datas = {this.state.datas} onRemoveData={this.onRemoveData} \/&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n\r\n});\r\n\r\nReactDOM.render(\r\n  &lt;RESTservice \/&gt;,\r\n  document.getElementById('content')\r\n);\r\n<\/pre>\n<p>Tarkastellaan yll\u00e4 olevassa koodissa muutamaa kohtaa:<\/p>\n<p>Ensinn\u00e4kin p\u00e4\u00e4komponentille (RESTService) on nyt lis\u00e4tty funktiot getInitialState() joka alustaa komponentin tilan sek\u00e4 componentDidMount() funtio joka lataa komponentin latautuessa datat REST palvelusta ja sijoittaa ne tilamuuttujaan. Lis\u00e4ksi p\u00e4\u00e4komponenttiin on lis\u00e4tty oma funktio onRemoveData(), joka tarjoaa datan poiston REST palvelupyynn\u00f6ll\u00e4.<\/p>\n<p>Riveill\u00e4 162 ja 163 n\u00e4emme esimerkin, miten tietoa voidaan v\u00e4litt\u00e4\u00e4 komponenttien v\u00e4lill\u00e4. Komponentille voidaan antaa nimettyj\u00e4 &#8221;propseja&#8221; eli &#8221;ominaisuuksia&#8221; (tai voisi kai niit\u00e4 sanoa jopa komponentin argumenteiksi). P\u00e4\u00e4komponentti siis v\u00e4litt\u00e4\u00e4 alikomponentille jotain tietoa, jota alikomponentti voi hy\u00f6dynt\u00e4\u00e4. V\u00e4litetty tieto voi olla konkreettista dataa mutta my\u00f6s funktioviite. Rivill\u00e4 162 v\u00e4litett\u00e4v\u00e4 <em>onDataAdded <\/em>-propsi on fuinktioviite. Rivill\u00e4 163 v\u00e4litett\u00e4v\u00e4 <em>datas<\/em> puolestaan on taulukkomuotoinen objekti. Alikomponentissa t\u00e4llaiseen nimettyyn propsiin viitataan nimell\u00e4, kuten rivill\u00e4 7. Itse asiassa rivill\u00e4 7 kyseinen funktioviite-propsi v\u00e4litet\u00e4\u00e4n edelleen listakomponentilta eteenp\u00e4in kullekin <strong>DataRow<\/strong> komponentille. T\u00e4lla tapaa kukin rivi voi kutsua p\u00e4\u00e4komponenttiin m\u00e4\u00e4ritelty\u00e4 funktiota kun Poista -painiketta painetaan.<\/p>\n<p>Rivill\u00e4 80 taas <strong>AddData<\/strong> komponentti k\u00e4ytt\u00e4\u00e4 saamaansa funktioviitett\u00e4 ja kutsuu funktiota kun on lis\u00e4nnyt dataa palveluun. T\u00e4ll\u00f6in p\u00e4\u00e4komponentti lataa tiedot uusimmat tiedot REST palvelusta ja p\u00e4ivitt\u00e4\u00e4 tilansa. T\u00e4st\u00e4 seuraa ett\u00e4 my\u00f6s p\u00e4\u00e4komponentin alaisuudessa (ks. rivi 163) oleva listauskomponentti eli <strong>DataList<\/strong> p\u00e4ivittyy &#8221;itsest\u00e4\u00e4n&#8221;, koska sille on v\u00e4litetty tietoa tilamuuttujan kautta!<\/p>\n<p>Riveill\u00e4 5-9 on mielenkiintoinen kohta. Siin\u00e4 <strong>DataList<\/strong> komponentti looppaa omassa Render funktiossaan saamansa datarivit l\u00e4pi ja muodostaa niiden pohjalta joukon <strong>DataRow <\/strong>komponentteja. Render funktion <em>return<\/em> -osuudesta n\u00e4emme, ett\u00e4 muodostettu joukko voidaan render\u00f6id\u00e4 k\u00e4stev\u00e4sti suoraan t\u00e4st\u00e4 muuttujasta (rivi 14).<\/p>\n<p>Toteutuksemme on nyt valmis! Jotta voimme kokeilla sit\u00e4 k\u00e4yt\u00e4nn\u00f6ss\u00e4, k\u00e4ynnist\u00e4mme ensin <a href=\"https:\/\/www.pilvikoodari.net\/?p=218\" target=\"_blank\">REST-blogipostauksessa<\/a> esitellyn yksinkertaisen REST palvelun.<\/p>\n<pre class=\"lang:default decode:true\">node simple-rest-servie.js<\/pre>\n<p>Sitten avataan selaimella index.html ja kokeillaan toiminnallisuutta.<\/p>\n<p>Tallennetaan uusi JSON data ja todetaan ett\u00e4 listaus todellakin p\u00e4ivittyy kun uusi JSON-data on tallennettu:<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example3.jpg\" rel=\"attachment wp-att-406\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-406\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example3.jpg\" alt=\"react_example3\" width=\"449\" height=\"769\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example3.jpg 449w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example3-175x300.jpg 175w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test2.jpg\" rel=\"attachment wp-att-408\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-408\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test2.jpg\" alt=\"react_example_test2\" width=\"449\" height=\"769\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test2.jpg 449w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test2-175x300.jpg 175w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><\/p>\n<p>Lis\u00e4t\u00e4\u00e4n viel\u00e4 toinenkin data ja n\u00e4hd\u00e4\u00e4n ett\u00e4 se tulee listaukseen mukaan:<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test3.jpg\" rel=\"attachment wp-att-409\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-409\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test3.jpg\" alt=\"react_example_test3\" width=\"449\" height=\"769\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test3.jpg 449w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test3-175x300.jpg 175w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><\/p>\n<p>Kokeillaan poistoa ja painetaan ylemm\u00e4n tietoalkion alapuolelta Poista. Kun poisto on tehty, listaus p\u00e4ivittyy ja listalla on en\u00e4\u00e4n yksi alkio:<\/p>\n<p><a href=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test4.jpg\" rel=\"attachment wp-att-410\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-410\" src=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test4.jpg\" alt=\"react_example_test4\" width=\"449\" height=\"769\" srcset=\"https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test4.jpg 449w, https:\/\/www.pilvikoodari.net\/wp-content\/uploads\/2016\/09\/react_example_test4-175x300.jpg 175w\" sizes=\"auto, (max-width: 449px) 100vw, 449px\" \/><\/a><\/p>\n<p><strong>Yhteenveto<\/strong><\/p>\n<p>T\u00e4ss\u00e4 blogipostauksessa tutustuimme Reactin ajattelutapaan ja k\u00e4sitteisiin sek\u00e4 kokeilimme React -ohjelmointia k\u00e4yt\u00e4nn\u00f6ss\u00e4. Kuten esimerkkimme kautta opimme, React tarjoaa varsin selke\u00e4n tavan web-sovelluksen rakenteen m\u00e4\u00e4ritt\u00e4miseen. Reactin &#8221;learnin curve&#8221; eli oppimisk\u00e4yr\u00e4 on varsin loiva eli simppelin React -toteutuksen tekeminen ja ymm\u00e4rt\u00e4minen on varsin helppoa. Yksisuuntainen datan sidonta pakottaa ohjelmoijan k\u00e4sittelem\u00e4\u00e4n sy\u00f6tteen itsen\u00e4isesti mutta render\u00f6inti sit\u00e4 vastoin tapahtuu automaattisesti.<\/p>\n<p>Yhteenvetona voisimme sanoa, ett\u00e4 Reactilla on varsin miellytt\u00e4v\u00e4\u00e4 toteuttaa Front-end -logiikkaa ja alkuun p\u00e4\u00e4see nopeasti ja helposti.<\/p>\n<p>Lis\u00e4tietoa Reactista l\u00f6yd\u00e4t <a href=\"https:\/\/facebook.github.io\/react\/docs\/getting-started.html\" target=\"_blank\">Reactin dokumentaatiosta<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Front-end ohjelmoinnissa on t\u00e4ll\u00e4 hetkell\u00e4 kaksi suurta ja kaunista frameworkkia: AngularJS ja ReactJS. Angular on Googlen kehitt\u00e4m\u00e4 framework ja ollut pidemp\u00e4\u00e4n k\u00e4yt\u00f6ss\u00e4 kuin React. React puolestaan on Facebookin alunperin kehitt\u00e4m\u00e4 ja saavuttanut nopeasti suuren suosion julkaisunsa j\u00e4lkeen. React on kehitetty suurien ja skaalautuvien web-palvelujen kehitt\u00e4miseen. Angularista on julkaistu vuonna 2016 uusi versio Angular 2, joka &#8230; <a title=\"React esittely\" class=\"read-more\" href=\"https:\/\/www.pilvikoodari.net\/?p=363\" aria-label=\"Lue lis\u00e4\u00e4 aiheesta React esittely\">Lue lis\u00e4\u00e4<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,14],"tags":[],"class_list":["post-363","post","type-post","status-publish","format-standard","hentry","category-json","category-react"],"_links":{"self":[{"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/posts\/363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=363"}],"version-history":[{"count":52,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/posts\/363\/revisions"}],"predecessor-version":[{"id":435,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=\/wp\/v2\/posts\/363\/revisions\/435"}],"wp:attachment":[{"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pilvikoodari.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}