Преобразование React.createClass в React.Component
В своей прошлой статье я рассказывал о патчинге старых версий React для работы в современной среде. В этой статье я пойду еще дальше и дам пошаговое руководство по обновлению классического компонента React до современного, заменив React.createClassспособ ведения дел на современный и предпочтительный React.Componentметод.
Нужные нам файлы будут находиться в папках «Исходный» и «Конечный» каталога компонентов в сопутствующем решении GitHub.
Получить учебные файлы с GitHub
Снова работа с компонентом [react-checkbox-list](https://github.com/sonyan/react-checkbox-list) Sony An (доступен как react-checkbox-listна npm ). В этом руководстве шаг за шагом показано, как заменить структуру и методы классического React.createClassкомпонента на современный React.Component.
Начиная с .jsxфайла в react-checkbox-listрешении, мы сначала удалим .jsфайл и переименуем его, .jsтак как .jsxфайлы больше не нужно называть по-другому.
Это дает нам следующий стартовый код:
'use strict';
var React = require('react');
module.exports = React.createClass({
displayName: 'CheckBoxList',
propTypes: {
defaultData: React.PropTypes.array,
onChange: React.PropTypes.func
},
getInitialState: function() {
return {
data: this.props.defaultData || []
};
},
handleItemChange: function(e) {
var selectedValues = [],
newData = [];
this.state.data.forEach(function(item) {
if(item.value === e.target.value) {
item.checked = e.target.checked;
}
if(item.checked) {
selectedValues.push(item.value);
}
newData.push(item);
});
this.setState({data: newData});
if(this.props.onChange) {
this.props.onChange(selectedValues);
}
},
reset: function() {
var newData = [];
this.state.data.forEach(function(item) {
item.checked = false;
newData.push(item);
});
this.setState({data: newData});
},
checkAll: function() {
var newData = [];
this.state.data.forEach(function(item) {
item.checked = true;
newData.push(item);
});
this.setState({data: newData});
},
render: function() {
var options;
options = this.state.data.map(function(item, index) {
return (<div key={'chk-' + index} className="checkbox">
<label>
<input
type="checkbox"
value={item.value}
onChange={this.handleItemChange}
checked={item.checked? true: false} /> {item.label}
</label>
</div>
);
}.bind(this));
return (<div>
{options}
</div>
);
}
});
Преобразование компонента
При попытке загрузить этот код первая ошибка, которую мы получаем,Uncaught Error: Module build failed: SyntaxError: The @jsx React.DOM pragma has been deprecated as of React 0.12
Uncaught Error: сбой сборки модуля: SyntaxError: прагма @jsx React.DOM устарела, начиная с React 0.12
Исправить это достаточно просто. Просто удалите строку /** @jsx React.DOM */из верхней части документа.
Теперь мы получаем ту Uncaught TypeError: Cannot read property 'array' of undefinedже ошибку, что и в учебнике по исправлению. Это связано с тем, что React.propTypes устарел в версии React 15.50, поэтому, согласно этому руководству, установите пакет PropTypes с помощью команды через npm. Мы импортируем это в наш пакет позже.[React.createClass](https://wholesomecode.ltd/blog/broken-react-createclass-component-lets-fix-it/)
npm install --save prop-types
Далее следует полная переработка кодовой базы, поэтому мы не можем обновить и исправить ошибку, как мы могли сделать ранее, поэтому мы не узнаем, сработало ли это до самого конца. Пристегнитесь!
Давайте начнем с замены React.createClassфункции, объявив новый React.Component. Измените наш код, чтобы он выглядел следующим образом:
'use strict';
import React from 'react';
class CheckBoxList extends React.Component {
...
}
Обратите внимание, что мы сделали здесь несколько вещей:
- Удален начальный комментарий JSX.
- Изменен тип объявления с
var React =...наimport React from 'react';это современный способ создания объявлений в React. - Теперь мы объявляем новый класс
CheckBoxListвместо экспорта функции. - Из-за синтаксиса объекта, который теперь заключен в круглые скобки
{...}, нам нужно удалить закрывающий);
Однако в этом новом классе теперь отсутствует способ экспорта, чтобы другие компоненты могли его использовать, поэтому давайте добавим объявление экспорта внизу этого кода.
'use strict';
import React from 'react';
class CheckBoxList extends React.Component {
...
}
export default CheckBoxList;
В нашем исходном коде первой строкой кода в функции был displayName: 'CheckBoxList',наш экспорт, который теперь обрабатывает это, поэтому мы можем полностью удалить этот код.
Следующая строка объявляет, что propTypesтеперь они находятся вне класса и нуждаются в PropTypesзависимости, которую мы добавили через npm. Давайте добавим это в наш импорт и напишем PropTypes так:
'use strict';
import React from 'react';
import PropTypes from 'prop-types';
class CheckBoxList extends React.Component {
...
}
CheckBoxList.propTypes = {
defaultData: PropTypes.array,
onChange: PropTypes.func,
};
export default CheckBoxList;
Затем состояние объявляется с помощью метода, getInitialStateи React.Componentмы устанавливаем наше начальное состояние с помощью конструктора. Добавьте в нашу сборку следующий код:
...
class CheckBoxList extends React.Component {
constructor( props) {
super( props );
this.state = {
data: [],
}
}
...
}
...
Вот и все, это устанавливает состояние компонента, но подождите, мы на самом деле не сказали ему, откуда взять его состояние. Вот где componentWillMountпригодится.
...
class CheckBoxList extends React.Component {
constructor( props) {
super( props );
this.state = {
data: [],
}
}
componentWillMount() {
this.setState({
data: this.props.defaultData,
});
}
...
}
...
Важно отметить, что внутренние методы React.Componentне заканчиваются запятыми (,), поэтому убедитесь, что любые методы, которые вы добавляете к компоненту, не заканчиваются запятой!
Далее, давайте добавим обратно функцию рендеринга. Это, наверное, самая простая часть, она почти такая же, с той ключевой разницей, что мы render: function() {просто меняем на render() {.
...
class CheckBoxList extends React.Component {
...
render() {
var options;
options = this.state.data.map(function(item, index) {
return (<div key={'chk-' + index} className="checkbox">
<label>
<input
type="checkbox"
value={item.value}
onChange={this.handleItemChange}
checked={item.checked? true: false} /> {item.label}
</label>
</div>
);
}.bind(this));
return (<div>
{options}
</div>
);
}
...
}
...
В целях сохранения актуальности этого руководства я не буду преобразовывать два метода resetи, checkAllтем не менее, концепции, используемые для порта метода handleItemChangeApple, в оба, поэтому не стесняйтесь попробовать их самостоятельно.
Чтобы перенести handleItemChangeметод, нам сначала нужно удалить закрывающую запятую (,) и изменить тип объявления функции с handleItemChange: function(e) {на handleItemChange( e) {убедившись, что мы по-прежнему передаем eего в качестве параметра события.
Давайте добавим это выше нашего метода рендеринга.
...
class CheckBoxList extends React.Component {
...
handleItemChange( e) {
var selectedValues = [],
newData = [];
this.state.data.forEach(function(item) {
if(item.value == e.target.value) {
item.checked = e.target.checked;
}
if(item.checked) {
selectedValues.push(item.value);
}
newData.push(item);
});
this.setState( {data: newData} );
if(this.props.onChange) {
this.props.onChange(selectedValues);
}
}
...
}
...
Теперь наш компонент будет отображаться, но не будет работать. Когда вы попытаетесь нажать на флажок, вы получите сообщение об ошибке Uncaught TypeError: Cannot read property 'state' of undefined.
Uncaught TypeError: невозможно прочитать состояние свойства неопределенного
Это потому, что в нашем handleItemChangeметоде, где мы пытаемся получить доступ к состоянию, thisоно не определено. Чтобы исправить это, нам нужно привязать нашу функцию к this, добавив следующую строку в наш конструктор: this.handleItemChange = this.handleItemChange.bind( this );.
...
class CheckBoxList extends React.Component {
constructor( props) {
super( props );
this.state = {
data: [],
}
this.handleItemChange = this.handleItemChange.bind( this );
}
...
}
...
И вот он, наш недавно преобразованный компонент React в действии.
React.createClass для React.Component
Исходный код учебника
Вы можете скачать исходный код оригинальной и финальной версии компонента на GitHub. Плагин содержит блок WordPress Gutenberg, который вы можете использовать для экспериментов с кодом, с тремя файлами, которые вы можете удалить, если это применимо:
Учебные файлы GitHub для преобразования React.createClass в React.Component