{"id":228649,"date":"2022-10-12T18:04:00","date_gmt":"2022-10-12T15:04:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228649"},"modified":"2022-11-09T03:32:41","modified_gmt":"2022-11-09T00:32:41","slug":"muunnetaan-react-createclass-react-componentiksi","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/fi\/muunnetaan-react-createclass-react-componentiksi\/","title":{"rendered":"Muunnetaan React.createClass React.Componentiksi"},"content":{"rendered":"\n<p>Edellisess\u00e4 <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">artikkelissani puhuin Reactin vanhempien versioiden korjaamisesta toimimaan nykyaikaisessa ymp\u00e4rist\u00f6ss\u00e4<\/a>. T\u00e4ss\u00e4 artikkelissa menen pidemm\u00e4lle ja annan vaiheittaisen oppaan klassisen React-komponentin p\u00e4ivitt\u00e4miseen nykyaikaiseksi vaihtamalla <code>React.createClass<\/code>asioiden tekeminen nykyaikaiseen ja suositumpaan <code>React.Component<\/code>menetelm\u00e4\u00e4n.<\/p>\n<p>Tarvitsemamme tiedostot ovat mukana tulevan GitHub-ratkaisun komponenttihakemiston &#8217;Original&#8217; ja &#8217;Final&#8217; kansioissa.<\/p>\n<p><a href=\"https:\/\/github.com\/mattwatsoncodes\/Tutorial-Convert-React-createClass-to-React-Component\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Hanki opetusohjelmatiedostot GitHubista<\/a><\/p>\n<p>Taas ty\u00f6skennell\u00e4\u00e4n <code>[react-checkbox-list](https:\/\/github.com\/sonyan\/react-checkbox-list)<\/code> <a href=\"https:\/\/github.com\/sonyan\/react-checkbox-list\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Sony Anin komponentin kanssa<\/a> (saatavana <a href=\"https:\/\/www.npmjs.com\/package\/react-checkbox-list\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\"><code>react-checkbox-list<\/code>npm<\/a> ). <code>React.createClass<\/code>T\u00e4m\u00e4 opas n\u00e4ytt\u00e4\u00e4 vaihe vaiheelta, kuinka klassisen komponentin rakenne ja menetelm\u00e4t korvataan modernilla <code>React.Component<\/code>.<\/p>\n<p>Alkaen ratkaisussa olevasta <code>.jsx<\/code>tiedostosta <code>react-checkbox-list<\/code>, poistamme ensin <code>.js<\/code>tiedoston ja nime\u00e4mme sen uudelleen muotoon, <code>.js<\/code>koska <code>.jsx<\/code>tiedostoja ei en\u00e4\u00e4 tarvitse nimet\u00e4 eri tavalla.<\/p>\n<p>T\u00e4m\u00e4 antaa meille seuraavan aloituskoodin:<\/p>\n<pre><code>\n'use strict';\nvar React = require('react');\n\nmodule.exports = React.createClass({\n    displayName: 'CheckBoxList',\n\n    propTypes: {\n        defaultData: React.PropTypes.array,\n        onChange: React.PropTypes.func\n    },\n\n    getInitialState: function() {\n        return {\n            data: this.props.defaultData || []\n        };\n    },\n\n    handleItemChange: function(e) {\n        var selectedValues = [],\n            newData = [];\n\n        this.state.data.forEach(function(item) {\n            if(item.value === e.target.value) {\n                item.checked = e.target.checked;\n            }\n            if(item.checked) {\n                selectedValues.push(item.value);\n            }\n            newData.push(item);\n        });\n\n        this.setState({data: newData});\n\n        if(this.props.onChange) {\n            this.props.onChange(selectedValues);\n        }\n    },\n\n    reset: function() {\n        var newData = [];\n        this.state.data.forEach(function(item) {\n            item.checked = false;\n            newData.push(item);\n        });\n\n        this.setState({data: newData});\n    },\n\n    checkAll: function() {\n        var newData = [];\n        this.state.data.forEach(function(item) {\n            item.checked = true;\n            newData.push(item);\n        });\n\n        this.setState({data: newData});\n    },\n\n    render: function() {\n        var options;\n\n        options = this.state.data.map(function(item, index) {\n            return (&lt;div key={'chk-' + index} className=\"checkbox\"&gt;\n                    &lt;label&gt;\n                        &lt;input\n                            type=\"checkbox\"\n                            value={item.value}\n                            onChange={this.handleItemChange}\n                            checked={item.checked? true: false} \/&gt; {item.label}\n                    &lt;\/label&gt;\n                &lt;\/div&gt;\n            );\n        }.bind(this));\n\n        return (&lt;div&gt;\n                {options}\n            &lt;\/div&gt;\n        );\n    }\n});\n<\/code><\/pre>\n<h2>Komponentin muuntaminen<\/h2>\n<p>Kun yrit\u00e4t ladata t\u00e4t\u00e4 koodia, ensimm\u00e4inen virhe, jonka saamme, on<code>Uncaught Error: Module build failed: SyntaxError: The @jsx React.DOM pragma has been deprecated as of React 0.12<\/code><\/p>\n<p>Tavoittamaton virhe: Moduulin rakennus ep\u00e4onnistui: SyntaxError: <a href=\"https:\/\/hashnode.com\/@jsx\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@jsx React.DOM-<\/a> k\u00e4yt\u00e4nt\u00f6 on vanhentunut React 0.12 :sta l\u00e4htien<\/p>\n<p>T\u00e4m\u00e4 on tarpeeksi yksinkertainen korjata. Poista vain viiva <code>\/** @jsx React.DOM *\/<\/code>asiakirjan yl\u00e4osasta.<\/p>\n<p>Saamme nyt saman <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">virheen<\/a><code>Uncaught TypeError: Cannot read property 'array' of undefined<\/code> kuin <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">korjausohjeessa<\/a>. T\u00e4m\u00e4 johtuu siit\u00e4, ett\u00e4 React.propTypes on vanhentunut Reactin versiossa 15.50, joten jatka t\u00e4m\u00e4n opetusohjelman mukaisesti ja asenna PropTypes-paketti komennolla npm:n kautta. Tuomme t\u00e4m\u00e4n pakettiin my\u00f6hemmin.<code>[React.createClass](https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/)<\/code><a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external\"><\/a><\/p>\n<pre><code>npm install --save prop-types\n<\/code><\/pre>\n<p>Nyt seuraa koodikannan t\u00e4ydellinen uudistus, joten emme voi p\u00e4ivitt\u00e4\u00e4 ja korjata virhett\u00e4, kuten olemme saaneet tehd\u00e4 aiemmin, joten emme tied\u00e4, onko se toiminut aivan loppuun asti. Kiinni!<\/p>\n<p>Aloitetaan korvaamalla <code>React.createClass<\/code>funktio ilmoittamalla uusi <code>React.Component<\/code>. Muuta koodiamme niin, ett\u00e4 se n\u00e4ytt\u00e4\u00e4 t\u00e4lt\u00e4:<\/p>\n<pre><code>'use strict';\nimport React from 'react';\n\nclass CheckBoxList extends React.Component {\n...\n}\n<\/code><\/pre>\n<p>Huomaa, ett\u00e4 olemme tehneet muutamia asioita t\u00e4\u00e4ll\u00e4:<\/p>\n<ul>\n<li>Poistettu avaava JSX-kommentti<\/li>\n<li>Ilmoitustyyppi muutettu <code>var React =...<\/code>t\u00e4h\u00e4n <code>import React from 'react';<\/code>on moderni tapa tehd\u00e4 ilmoituksia Reactissa.<\/li>\n<li>Ilmoitamme nyt uuden luokan <code>CheckBoxList<\/code>funktion viemisen sijaan.<\/li>\n<li>Suluissa olevan objektin syntaksin vuoksi <code>{...}<\/code>meid\u00e4n on hyl\u00e4tt\u00e4v\u00e4 sulkemis<code>);<\/code><\/li>\n<\/ul>\n<p>T\u00e4st\u00e4 uudesta luokasta puuttuu kuitenkin nyt tapa vied\u00e4 sit\u00e4, jotta muut komponentit voivat k\u00e4ytt\u00e4\u00e4 sit\u00e4, joten lis\u00e4t\u00e4\u00e4n vienti-ilmoitus koodin alaosaan.<\/p>\n<pre><code>'use strict';\nimport React from 'react';\n\nclass CheckBoxList extends React.Component {\n...\n}\n\nexport default CheckBoxList;\n<\/code><\/pre>\n<p>Alkuper\u00e4isess\u00e4 koodissamme funktion ensimm\u00e4inen koodirivi oli, <code>displayName: 'CheckBoxList',<\/code>ett\u00e4 vientimme k\u00e4sittelee nyt t\u00e4m\u00e4n, joten voimme poistaa koodin kokonaan.<\/p>\n<p>Seuraava rivi alas ilmoittaa, ett\u00e4 <code>propTypes<\/code>n\u00e4m\u00e4 istuvat nyt luokan ulkopuolella ja tarvitsevat <code>PropTypes<\/code>riippuvuuden, jonka lis\u00e4simme npm:n kautta. Lis\u00e4t\u00e4\u00e4n se tuontiin ja kirjoitetaan PropTypes n\u00e4in:<\/p>\n<pre><code>'use strict';\nimport React from 'react';\nimport PropTypes from 'prop-types';\n\nclass CheckBoxList extends React.Component {\n...\n}\n\nCheckBoxList.propTypes = {\n    defaultData: PropTypes.array,\n    onChange: PropTypes.func,\n};\n\nexport default CheckBoxList;\n<\/code><\/pre>\n<p>Seuraavaksi tila ilmoitetaan menetelm\u00e4ll\u00e4 <code>getInitialState<\/code>, jossa <code>React.Component<\/code>asetamme alkutilan konstruktorilla. Lis\u00e4\u00e4 seuraava koodi rakentamiseen:<\/p>\n<pre><code>...\nclass CheckBoxList extends React.Component {\n    constructor( props) {\n        super( props );\n        this.state = {\n            data: [],\n        }\n    }\n...\n}\n...\n<\/code><\/pre>\n<p>Siin\u00e4 menn\u00e4\u00e4n, se m\u00e4\u00e4ritt\u00e4\u00e4 komponentin tilan, mutta odota, emme ole kertoneet sille, mist\u00e4 sen tila saa. Siell\u00e4 se <code>componentWillMount<\/code>on hy\u00f6dyllist\u00e4.<\/p>\n<pre><code>...\nclass CheckBoxList extends React.Component {\n    constructor( props) {\n        super( props );\n        this.state = {\n            data: [],\n        }\n    }\n\n    componentWillMount() {\n        this.setState({\n            data: this.props.defaultData,\n        });\n    }\n...\n}\n...\n<\/code><\/pre>\n<p>T\u00e4rkeint\u00e4 on huomata, ett\u00e4 sis\u00e4iset menetelm\u00e4t <code>React.Component<\/code>eiv\u00e4t p\u00e4\u00e4ty pilkkuihin (<code>,<\/code>), joten varmista, ett\u00e4 komponenttiin lis\u00e4\u00e4m\u00e4si menetelm\u00e4t eiv\u00e4t p\u00e4\u00e4ty pilkkuun!<\/p>\n<p>Lis\u00e4t\u00e4\u00e4n seuraavaksi render\u00f6intitoiminto takaisin. T\u00e4m\u00e4 on luultavasti helpoin osa, se on melkein sama, sill\u00e4 keskeinen ero, ett\u00e4 muutamme <code>render: function() {<\/code>vain <code>render() {<\/code>.<\/p>\n<pre><code>...\nclass CheckBoxList extends React.Component {\n...\n    render() {\n        var options;\n\n        options = this.state.data.map(function(item, index) {\n            return (&lt;div key={'chk-' + index} className=\"checkbox\"&gt;\n                    &lt;label&gt;\n                        &lt;input\n                            type=\"checkbox\"\n                            value={item.value}\n                            onChange={this.handleItemChange}\n                            checked={item.checked? true: false} \/&gt; {item.label}\n                    &lt;\/label&gt;\n                &lt;\/div&gt;\n            );\n        }.bind(this));\n\n        return (&lt;div&gt;\n                {options}\n            &lt;\/div&gt;\n        );\n    }\n...\n}\n...\n<\/code><\/pre>\n<p>Jotta t\u00e4m\u00e4 opetusohjelma pysyy asian ytimess\u00e4, en muunna kahta menetelm\u00e4\u00e4 <code>reset<\/code>ja menetelm\u00e4omenan <code>checkAll<\/code>portissa k\u00e4ytettyj\u00e4 k\u00e4sitteit\u00e4 <code>handleItemChange<\/code>molemmiksi, joten voit vapaasti kokeilla niit\u00e4 itse.<\/p>\n<p>Menetelm\u00e4n siirt\u00e4miseksi <code>handleItemChange<\/code>meid\u00e4n on ensin poistettava sulkeva pilkku (<code>,<\/code>) ja muutettava funktion ilmoitustyyppi -asennosta <code>handleItemChange: function(e) {<\/code>varmistaaksemme <code>handleItemChange( e) {<\/code>, ett\u00e4 k\u00e4yt\u00e4mme edelleen <code>e<\/code>tapahtumaparametria.<\/p>\n<p>Lis\u00e4t\u00e4\u00e4n se renderointimenetelm\u00e4mme yl\u00e4puolelle.<\/p>\n<pre><code>...\nclass CheckBoxList extends React.Component {\n...\n    handleItemChange( e) {\n        var selectedValues = [],\n            newData = [];\n\n        this.state.data.forEach(function(item) {\n            if(item.value == e.target.value) {\n                item.checked = e.target.checked;\n            }\n            if(item.checked) {\n                selectedValues.push(item.value);\n            }\n            newData.push(item);\n        });\n\n        this.setState( {data: newData} );\n\n        if(this.props.onChange) {\n            this.props.onChange(selectedValues);\n        }\n    }\n...\n}\n...\n<\/code><\/pre>\n<p>Komponenttimme hahmonnetaan nyt, mutta se ei toimi. Kun yrit\u00e4t napsauttaa valintaruutua, saat virheilmoituksen <code>Uncaught TypeError: Cannot read property 'state' of undefined<\/code>.<\/p>\n<p>Uncaught TypeError: M\u00e4\u00e4ritt\u00e4m\u00e4tt\u00f6m\u00e4n ominaisuuden &#8217;state&#8217; lukeminen ep\u00e4onnistui<\/p>\n<p>T\u00e4m\u00e4 johtuu siit\u00e4, ett\u00e4 <code>handleItemChange<\/code>menetelm\u00e4ss\u00e4mme, jossa yrit\u00e4mme p\u00e4\u00e4st\u00e4 tilaan, <code>this<\/code>on m\u00e4\u00e4rittelem\u00e4t\u00f6n. Korjataksemme t\u00e4m\u00e4n meid\u00e4n t\u00e4ytyy sitoa funktiomme <code>this<\/code>lis\u00e4\u00e4m\u00e4ll\u00e4 seuraava rivi konstruktoriimme: <code>this.handleItemChange = this.handleItemChange.bind( this );<\/code>.<\/p>\n<pre><code>...\nclass CheckBoxList extends React.Component {\n    constructor( props) {\n        super( props );\n        this.state = {\n            data: [],\n        }\n        this.handleItemChange = this.handleItemChange.bind( this );\n    }\n...\n}\n...\n<\/code><\/pre>\n<p>Ja siell\u00e4 se on, juuri muunnettu React-komponenttimme toiminnassa.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f22b2772.gif\" alt=\"Muunnetaan React.createClass React.Componentiksi\" \/>React.createClass to React.Component<\/p>\n<h2>Opetusohjelman l\u00e4hdekoodi<\/h2>\n<p>Voit <a href=\"https:\/\/github.com\/wholesomecode\/Tutorial-Convert-React-createClass-to-React-Component\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">ladata komponentin alkuper\u00e4isen ja lopullisen version l\u00e4hdekoodin GitHubista<\/a>. Laajennus sis\u00e4lt\u00e4\u00e4 WordPress Gutenberg -lohkon, jonka avulla voit leikki\u00e4 koodilla kolmella tiedostolla, jotka voit poistaa tarpeen mukaan:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f247b7d4.png\" alt=\"Muunnetaan React.createClass React.Componentiksi\" \/>GitHub-opetustiedostot React.createClass to React.Component -muunnokselle<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Edellisess\u00e4 artikkelissani puhuin Reactin vanhempien versioiden korjaamisesta toimimaan nykyaikaisessa ymp\u00e4rist\u00f6ss\u00e4. T\u00e4ss\u00e4 artikkelissa menen viel\u00e4 pidemm\u00e4lle ja annan vaiheittaisen oppaan cl&#8230;<\/p>\n","protected":false},"author":1,"featured_media":224207,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[719,895,917,843],"tags":[1166],"class_list":["post-228649","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-kehittaejae","category-koodi","category-muut","category-opetusohjelmia","tag-affiai-fi"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts\/228649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/comments?post=228649"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts\/228649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/media\/224207"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/media?parent=228649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/categories?post=228649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/tags?post=228649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}