{"id":228516,"date":"2022-10-12T18:54:00","date_gmt":"2022-10-12T15:54:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228516"},"modified":"2022-11-09T02:48:49","modified_gmt":"2022-11-08T23:48:49","slug":"convertendo-react-createclass-para-react-component","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pt-pt\/convertendo-react-createclass-para-react-component\/","title":{"rendered":"Convertendo React.createClass para React.Component"},"content":{"rendered":"\n<p>No meu <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">\u00faltimo artigo falei sobre como corrigir vers\u00f5es mais antigas do React para funcionar em um ambiente moderno<\/a>. Neste artigo vou mais longe e dou um guia passo a passo para atualizar um componente React cl\u00e1ssico para um moderno, mudando a <code>React.createClass<\/code>maneira de fazer as coisas para o m\u00e9todo moderno e preferido <code>React.Component<\/code>.<\/p>\n<p>Os arquivos que precisamos estar\u00e3o nas pastas &#8216;Original&#8217; e &#8216;Final&#8217; do diret\u00f3rio de componentes na solu\u00e7\u00e3o GitHub que acompanha.<\/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\">Obter arquivos de tutorial do GitHub<\/a><\/p>\n<p>Novamente trabalhando com o componente <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\">da Sony An<\/a> (dispon\u00edvel como <a href=\"https:\/\/www.npmjs.com\/package\/react-checkbox-list\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\"><code>react-checkbox-list<\/code>em npm<\/a> ). Este guia mostra passo a passo como substituir a estrutura e os m\u00e9todos de um <code>React.createClass<\/code>componente cl\u00e1ssico por um moderno <code>React.Component<\/code>.<\/p>\n<p>Come\u00e7ando com o <code>.jsx<\/code>arquivo na <code>react-checkbox-list<\/code>solu\u00e7\u00e3o, primeiro vamos excluir o <code>.js<\/code>arquivo e renome\u00e1-lo, <code>.js<\/code>pois os <code>.jsx<\/code>arquivos n\u00e3o precisam mais ser nomeados de forma diferente.<\/p>\n<p>Isso nos d\u00e1 o seguinte c\u00f3digo inicial:<\/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>Convertendo o componente<\/h2>\n<p>Ao tentar carregar este c\u00f3digo, o primeiro erro que recebemos \u00e9<code>Uncaught Error: Module build failed: SyntaxError: The @jsx React.DOM pragma has been deprecated as of React 0.12<\/code><\/p>\n<p>Erro n\u00e3o capturado: Falha na compila\u00e7\u00e3o do m\u00f3dulo: SyntaxError: O pragma <a href=\"https:\/\/hashnode.com\/@jsx\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@jsx<\/a> React.DOM foi preterido a partir do React 0.12<\/p>\n<p>\u00c9 simples o suficiente para corrigir isso. Basta remover a linha <code>\/** @jsx React.DOM *\/<\/code>da parte superior do documento.<\/p>\n<p>Agora temos <code>Uncaught TypeError: Cannot read property 'array' of undefined<\/code>o mesmo erro do <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tutorial de<\/a> <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">patch<\/a>. Isso ocorre porque o React.propTypes foi preterido na vers\u00e3o 15.50 do React, ent\u00e3o de acordo com esse tutorial, v\u00e1 em frente e instale o pacote PropTypes com o comando via npm. Vamos importar isso para o nosso pacote mais tarde.<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>O que se segue agora \u00e9 uma revis\u00e3o completa da base de c\u00f3digo, ent\u00e3o n\u00e3o podemos atualizar e corrigir um erro como fizemos anteriormente, ent\u00e3o n\u00e3o saberemos se funcionou at\u00e9 o final. Preparar-se!<\/p>\n<p>Vamos come\u00e7ar substituindo a <code>React.createClass<\/code>fun\u00e7\u00e3o declarando um novo <code>React.Component<\/code>. Altere nosso c\u00f3digo para que fique assim:<\/p>\n<pre><code>'use strict';\nimport React from 'react';\n\nclass CheckBoxList extends React.Component {\n...\n}\n<\/code><\/pre>\n<p>Observe que fizemos algumas coisas aqui:<\/p>\n<ul>\n<li>Removido o coment\u00e1rio JSX de abertura<\/li>\n<li>Alterado o tipo de declara\u00e7\u00e3o <code>var React =...<\/code>para <code>import React from 'react';<\/code>este \u00e9 a maneira moderna de fazer declara\u00e7\u00f5es no React.<\/li>\n<li>Agora declaramos uma nova classe de <code>CheckBoxList<\/code>, em vez de exportar uma fun\u00e7\u00e3o.<\/li>\n<li>Devido \u00e0 sintaxe do objeto agora estar entre par\u00eanteses <code>{...}<\/code>, precisamos descartar o fechamento<code>);<\/code><\/li>\n<\/ul>\n<p>No entanto, esta nova classe agora est\u00e1 faltando uma maneira de export\u00e1-la para que outros componentes possam us\u00e1-la, ent\u00e3o vamos adicionar uma declara\u00e7\u00e3o de exporta\u00e7\u00e3o na parte inferior desse c\u00f3digo.<\/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>Em nosso c\u00f3digo original, a primeira linha de c\u00f3digo na fun\u00e7\u00e3o era <code>displayName: 'CheckBoxList',<\/code>nossa exporta\u00e7\u00e3o agora lida com isso, para que possamos remover esse c\u00f3digo completamente.<\/p>\n<p>A pr\u00f3xima linha declara <code>propTypes<\/code>que estes agora est\u00e3o fora da classe e precisam da <code>PropTypes<\/code>depend\u00eancia que adicionamos via npm. Vamos adicionar isso em nossas importa\u00e7\u00f5es e escrever os PropTypes assim:<\/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>Em seguida, o estado \u00e9 declarado atrav\u00e9s do m\u00e9todo <code>getInitialState<\/code>com <code>React.Component<\/code>que definimos nosso estado inicial com um construtor. Adicione o seguinte c\u00f3digo em nossa compila\u00e7\u00e3o:<\/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>L\u00e1 vamos n\u00f3s, que configura o estado do componente, mas espere, n\u00f3s ainda n\u00e3o dissemos a ele de onde obter seu estado. \u00c9 a\u00ed que <code>componentWillMount<\/code>vem a calhar.<\/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>Uma coisa importante a ser observada \u00e9 que os m\u00e9todos internos de <code>React.Component<\/code>n\u00e3o terminam em v\u00edrgulas (<code>,<\/code>), portanto, certifique-se de que quaisquer m\u00e9todos adicionados ao componente n\u00e3o terminem em v\u00edrgula!<\/p>\n<p>Em seguida, vamos adicionar a fun\u00e7\u00e3o de renderiza\u00e7\u00e3o de volta. Esta \u00e9 provavelmente a parte mais f\u00e1cil, \u00e9 quase a mesma coisa, com a diferen\u00e7a chave que mudamos <code>render: function() {<\/code>para apenas <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>Para fins de manter este tutorial direto ao ponto, n\u00e3o converterei os dois m\u00e9todos <code>reset<\/code>e, <code>checkAll<\/code>no entanto, os conceitos usados \u200b\u200bpara a porta do m\u00e9todo <code>handleItemChange<\/code>apple para ambos, portanto, sinta-se \u00e0 vontade para experiment\u00e1-los.<\/p>\n<p>Para migrar o <code>handleItemChange<\/code>m\u00e9todo, primeiro precisamos remover a v\u00edrgula de fechamento (<code>,<\/code>) e alterar o tipo de declara\u00e7\u00e3o da fun\u00e7\u00e3o <code>handleItemChange: function(e) {<\/code>para <code>handleItemChange( e) {<\/code>garantir que ainda passemos <code>e<\/code>como par\u00e2metro do evento.<\/p>\n<p>Vamos adicionar isso acima do nosso m\u00e9todo de renderiza\u00e7\u00e3o.<\/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>Nosso componente agora ser\u00e1 renderizado, por\u00e9m n\u00e3o ser\u00e1 funcional. Ao tentar clicar em uma caixa de sele\u00e7\u00e3o, voc\u00ea receber\u00e1 o erro <code>Uncaught TypeError: Cannot read property 'state' of undefined<\/code>.<\/p>\n<p>Erro de tipo n\u00e3o capturado: n\u00e3o \u00e9 poss\u00edvel ler a propriedade &#8216;estado&#8217; de indefinido<\/p>\n<p>Isso porque em nosso <code>handleItemChange<\/code>m\u00e9todo, onde tentamos acessar o estado, <code>this<\/code>\u00e9 indefinido. Para corrigir isso, precisamos vincular nossa fun\u00e7\u00e3o <code>this<\/code>adicionando a seguinte linha em nosso construtor: <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>E a\u00ed est\u00e1, nosso rec\u00e9m-convertido componente React em a\u00e7\u00e3o.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f22b2772.gif\" alt=\"Convertendo React.createClass para React.Component\" \/>React.createClass para React.Component<\/p>\n<h2>C\u00f3digo-fonte do tutorial<\/h2>\n<p>Voc\u00ea pode <a href=\"https:\/\/github.com\/wholesomecode\/Tutorial-Convert-React-createClass-to-React-Component\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">baixar o c\u00f3digo-fonte da vers\u00e3o original e final do componente no GitHub<\/a>. O plugin cont\u00e9m um bloco WordPress Gutenberg que voc\u00ea pode usar para brincar com o c\u00f3digo, com tr\u00eas arquivos que voc\u00ea pode excluir conforme aplic\u00e1vel:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f247b7d4.png\" alt=\"Convertendo React.createClass para React.Component\" \/>Os arquivos de tutorial do GitHub para a convers\u00e3o de React.createClass para React.Component<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fonte de grava\u00e7\u00e3o:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>No meu \u00faltimo artigo, falei sobre como corrigir vers\u00f5es mais antigas do React para funcionar em um ambiente moderno. Neste artigo vou mais longe e dou um guia passo a passo para atualizar um 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":[898,722,920,846],"tags":[1170],"class_list":["post-228516","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo-2","category-desenvolvedor","category-outro","category-tutoriais","tag-affiai-pt-pt"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/228516","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=228516"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/228516\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media\/224207"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=228516"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/categories?post=228516"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/tags?post=228516"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}