{"id":228185,"date":"2022-10-12T18:52:00","date_gmt":"2022-10-12T15:52:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228185"},"modified":"2022-11-09T01:10:48","modified_gmt":"2022-11-08T22:10:48","slug":"conversion-de-react-createclass-a-react-component","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/es\/conversion-de-react-createclass-a-react-component\/","title":{"rendered":"Conversi\u00f3n de React.createClass a React.Component"},"content":{"rendered":"\n<p>En mi <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">\u00faltimo art\u00edculo habl\u00e9 sobre parchear versiones anteriores de React para que funcionen en un entorno moderno<\/a>. En este art\u00edculo voy m\u00e1s all\u00e1 y doy una gu\u00eda paso a paso para actualizar un componente React cl\u00e1sico a uno moderno, cambiando la <code>React.createClass<\/code>forma de hacer las cosas al <code>React.Component<\/code>m\u00e9todo moderno y preferido.<\/p>\n<p>Los archivos que necesitamos estar\u00e1n en las carpetas &#8216;Original&#8217; y &#8216;Final&#8217; del directorio de componentes en la soluci\u00f3n GitHub adjunta.<\/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\">Obtener archivos de tutoriales de GitHub<\/a><\/p>\n<p>Nuevamente trabajando con el 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\">de Sony An<\/a> (disponible <a href=\"https:\/\/www.npmjs.com\/package\/react-checkbox-list\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\"><code>react-checkbox-list<\/code>en npm<\/a> ). Esta gu\u00eda le muestra paso a paso c\u00f3mo reemplazar la estructura y los m\u00e9todos de un <code>React.createClass<\/code>componente cl\u00e1sico a uno moderno <code>React.Component<\/code>.<\/p>\n<p>Comenzando con el <code>.jsx<\/code>archivo en la <code>react-checkbox-list<\/code>soluci\u00f3n, primero eliminaremos el <code>.js<\/code>archivo y cambiaremos su nombre para <code>.js<\/code>que los <code>.jsx<\/code>archivos ya no necesiten tener un nombre diferente.<\/p>\n<p>Eso nos da el siguiente c\u00f3digo de inicio:<\/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>Convertir el componente<\/h2>\n<p>Al intentar cargar este c\u00f3digo, el primer error que obtenemos es<code>Uncaught Error: Module build failed: SyntaxError: The @jsx React.DOM pragma has been deprecated as of React 0.12<\/code><\/p>\n<p>Error no detectado: Fall\u00f3 la construcci\u00f3n del m\u00f3dulo: SyntaxError: el pragma <a href=\"https:\/\/hashnode.com\/@jsx\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@jsx<\/a> React.DOM ha quedado obsoleto a partir de React 0.12<\/p>\n<p>Es bastante simple corregir esto. Simplemente elimine la l\u00ednea <code>\/** @jsx React.DOM *\/<\/code>de la parte superior del documento.<\/p>\n<p>Ahora obtenemos el mismo error <code>Uncaught TypeError: Cannot read property 'array' of undefined<\/code>que en el <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tutorial de aplicaci\u00f3n de<\/a> <a href=\"https:\/\/wholesomecode.ltd\/blog\/broken-react-createclass-component-lets-fix-it\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">parches<\/a>. Esto se debe a que React.propTypes qued\u00f3 obsoleto en la versi\u00f3n 15.50 de React, as\u00ed que seg\u00fan ese tutorial, contin\u00fae e instale el paquete PropTypes con el comando a trav\u00e9s de npm. Importaremos esto en nuestro paquete m\u00e1s 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>Lo que sigue ahora es una revisi\u00f3n completa del c\u00f3digo base, por lo que no podemos actualizar y corregir un error como lo hicimos anteriormente, por lo que no sabremos si funcion\u00f3 hasta el final. \u00a1Cintur\u00f3n de seguridad!<\/p>\n<p>Comencemos reemplazando la <code>React.createClass<\/code>funci\u00f3n declarando un nuevo <code>React.Component<\/code>. Modifique nuestro c\u00f3digo para que se vea como lo siguiente:<\/p>\n<pre><code>'use strict';\nimport React from 'react';\n\nclass CheckBoxList extends React.Component {\n...\n}\n<\/code><\/pre>\n<p>Tenga en cuenta que hemos hecho algunas cosas aqu\u00ed:<\/p>\n<ul>\n<li>Se elimin\u00f3 el comentario JSX de apertura.<\/li>\n<li>Alter\u00f3 el tipo de declaraci\u00f3n de <code>var React =...<\/code>a <code>import React from 'react';<\/code>esta es la forma moderna de hacer declaraciones en React.<\/li>\n<li>Ahora declaramos una nueva clase de <code>CheckBoxList<\/code>, en lugar de exportar una funci\u00f3n.<\/li>\n<li>Debido a que la sintaxis del objeto ahora est\u00e1 encerrado entre par\u00e9ntesis <code>{...}<\/code>, debemos eliminar el cierre<code>);<\/code><\/li>\n<\/ul>\n<p>Sin embargo, a esta nueva clase ahora le falta una forma de exportarla para que otros componentes puedan usarla, as\u00ed que agreguemos una declaraci\u00f3n de exportaci\u00f3n en la parte inferior de ese 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>En nuestro c\u00f3digo original, la primera l\u00ednea de c\u00f3digo en la funci\u00f3n era <code>displayName: 'CheckBoxList',<\/code>nuestra exportaci\u00f3n ahora maneja esto, por lo que podemos eliminar ese c\u00f3digo por completo.<\/p>\n<p>La siguiente l\u00ednea hacia abajo declara que <code>propTypes<\/code>estos ahora se encuentran fuera de la clase y necesitan la <code>PropTypes<\/code>dependencia que agregamos a trav\u00e9s de npm. Agreguemos eso a nuestras importaciones y escribamos los PropTypes as\u00ed:<\/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>A continuaci\u00f3n, el estado se declara a trav\u00e9s del m\u00e9todo <code>getInitialState<\/code>con el <code>React.Component<\/code>que establecemos nuestro estado inicial con un constructor. Agregue el siguiente c\u00f3digo en nuestra compilaci\u00f3n:<\/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>Ah\u00ed vamos, eso establece el estado del componente, pero espera, en realidad no le hemos dicho de d\u00f3nde obtener su estado. Ah\u00ed es donde <code>componentWillMount<\/code>viene bien.<\/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>Una cosa clave a tener en cuenta es que los m\u00e9todos internos de <code>React.Component<\/code>no terminan en comas (<code>,<\/code>), \u00a1as\u00ed que aseg\u00farese de que cualquier m\u00e9todo que agregue al componente no termine en coma!<\/p>\n<p>A continuaci\u00f3n, volvamos a agregar la funci\u00f3n de renderizado. Esta es probablemente la parte m\u00e1s f\u00e1cil, es casi lo mismo, con la diferencia clave de que cambiamos <code>render: function() {<\/code>a solo <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>Con el fin de mantener este tutorial al grano, no convertir\u00e9 los dos m\u00e9todos <code>reset<\/code>y, <code>checkAll<\/code>sin embargo, los conceptos utilizados para el puerto del m\u00e9todo <code>handleItemChange<\/code>apple a ambos, as\u00ed que no dude en intentarlos usted mismo.<\/p>\n<p>Para migrar el <code>handleItemChange<\/code>m\u00e9todo, primero debemos eliminar la coma de cierre (<code>,<\/code>) y modificar el tipo de declaraci\u00f3n de la funci\u00f3n <code>handleItemChange: function(e) {<\/code>para <code>handleItemChange( e) {<\/code>asegurarnos de que a\u00fan lo pasemos <code>e<\/code>como el par\u00e1metro del evento.<\/p>\n<p>Agreguemos eso arriba de nuestro m\u00e9todo de renderizado.<\/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>Nuestro componente ahora se renderizar\u00e1, sin embargo, no ser\u00e1 funcional. Cuando intente hacer clic en una casilla de verificaci\u00f3n, obtendr\u00e1 el error <code>Uncaught TypeError: Cannot read property 'state' of undefined<\/code>.<\/p>\n<p>TypeError no capturado: no se puede leer la propiedad &#8216;estado&#8217; de indefinido<\/p>\n<p>Esto se debe a que en nuestro <code>handleItemChange<\/code>m\u00e9todo, donde intentamos acceder al estado, <code>this<\/code>no est\u00e1 definido. Para solucionar esto, debemos vincular nuestra funci\u00f3n <code>this<\/code>agregando la siguiente l\u00ednea en nuestro constructor: <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>Y ah\u00ed lo tenemos, nuestro componente React reci\u00e9n convertido en acci\u00f3n.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f22b2772.gif\" alt=\"Conversi\u00f3n de React.createClass a React.Component\" \/>React.createClass a React.Component<\/p>\n<h2>C\u00f3digo fuente del tutorial<\/h2>\n<p>Puede <a href=\"https:\/\/github.com\/wholesomecode\/Tutorial-Convert-React-createClass-to-React-Component\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">descargar el c\u00f3digo fuente de la versi\u00f3n original y final del componente en GitHub<\/a>. El complemento contiene un bloque de WordPress Gutenberg que puede usar para jugar con el c\u00f3digo, con tres archivos que puede eliminar seg\u00fan corresponda:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169430-61e80f247b7d4.png\" alt=\"Conversi\u00f3n de React.createClass a React.Component\" \/>Los archivos de tutorial de GitHub para la conversi\u00f3n de React.createClass a React.Component<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fuente de grabaci\u00f3n:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>En mi \u00faltimo art\u00edculo habl\u00e9 sobre parchear versiones anteriores de React para que funcionen en un entorno moderno. En este art\u00edculo voy m\u00e1s all\u00e1 y brindo una gu\u00eda paso a paso para actualizar un 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":[892,716,914,840],"tags":[1172],"class_list":["post-228185","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo","category-desarrollador","category-otro","category-tutoriales","tag-affiai-es"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228185","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/comments?post=228185"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228185\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media\/224207"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media?parent=228185"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/categories?post=228185"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/tags?post=228185"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}