ReactJS — это огромная библиотека пользовательского интерфейса (не фрэймворк), завоевавшая большую любовь. Как-то разговаривая с коллегой/другом о ReactJS я услышал от него, что работа с ReactJS не такая интересная, поскольку там слишком много вариантов решения для одной задачи. После некоторого изучения и случайных собеседований я понял, что это как раз таки одна из причин, по которой разработчики сталкиваются с проблемами при работе с этой библиотекой.
Различные способы создания и управления компонентом React, куча инструментов управления, и многое другое и есть центр этих проблем. Всё, что мы можем сегодня сделать, это привести наиболее распространенные способы решения задач (основанные на выборе людей) и обсудить их.
Заодно мы пробежимся по некоторым полезным темам и терминам в React, которые иногда пугают новичков. А вот темы:
- Компонент Родитель
- Валидация свойств компонентов
- Взаимодействие компонентов
- Компонент со значением по умолчанию
- ES6+ Компоненты (и различие от normal компонентов)
- Бесструктурные компоненты
Это статья содержит только базу, поэтому возможно информация эта для вас окажется простой и не новой. Если вы ищете более сложные темы, то вы можете пройтись по нашим многочисленным статьям о ReactJS.
- # Стандартный компонент React
- # States и Props
- # Компонент Родитель
- # Взаимодействие компонентов
- # Компонент со значением по умолчанию
- # Валидация свойств компонентов
- # Компонент Класс (ES6)
- Установка состояний с классами
- PROPS ПО УМОЛЧАНИЮ И ВАЛИДАЦИЯ С ИСПОЛЬЗОВАНИЕМ КЛАССОМ
- # Бесструктурные компоненты
- # Заключение
# Стандартный компонент React
Под стандартным компонентом я имею в виду то, что вы возможно, видели в большинстве репозиториев кода и статей:
1
2
3
4
5
6
7
8
9
10
|
var Hello = React.createClass({
render: function() {
return <div>Hello {this.props.name};
}
});
ReactDOM.render
( <Hello name=«World» />,
document.getElementById(‘container’)
);
|
render
является самым важным и обязательным свойством. Оно отвечает за парсинг HTML-кода в JavaScript, JSX.
1
|
<h1>My name is {name}</h1>
|
1
|
<Hello name=«World» />
|
# States и Props
Динамические приложения должны передавать данные между собой. В React передача данных происходит в основном между компонентами и внешними сервисами, которые предоставляют исходные данные (например, по протоколу HTTP, localstorage).
Свойства (Props) являются неизменными, а значит, они могут только передаваться от родительских компонентов и не могут быть изменены. Это создает проблему, потому что современные приложения не располагают всеми данными при загрузке страницы, ведь AJAX запросы или события могут произойти потом, и когда вернутся данные, кто-то должен быть ответственным за обновление. Вот тут и приходят состояний (states).
На этапе инициализации React мы определяем исходное состояние (state) и свойства (props). Как только состояние обновляется, свойства (props) могут быть легко обновлены:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
var Counter = React.createClass({
getInitialState: function() {
return {
counter: 0
};
},
render: function() {
return <div>
<h2>{this.props.name}</h2>
{this.state.counter}
</div>;
}
});
ReactDOM.render(
<Counter name={‘Counter’} />,
document.getElementById(‘container’)
);
|
# Компонент Родитель
Тут всё довольно понятно. Если компонент рендерит другой компонент в своем методе render, то он это собственник (родитель). Родитель имеет над компонентом контроль.
Давайте взглянем на другой пример:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
var CounterDisplay = React.createClass({
render: function(){
return <div>{this.props.counterProp}</div>
}
})
var Counter = React.createClass({
getInitialState: function() {
return {
counter: 0
};
},
render: function() {
// React выдаст ошибку, если у DOM нет единственного родителя
return <div>
<h2>{this.props.name}</h2>
<CounterDisplay counterProp={this.state.counter}></CounterDisplay>
</div>;
}
});
ReactDOM.render(
<Counter name={‘Counter’} />,
document.getElementById(‘container’)
);
|
Свойство Counter передается в другой компонент, CounterDisplay. Вы можете увидеть, как мы передаем состояние дочернему компонента через свойства.
# Взаимодействие компонентов
А что если бы у нас была кнопка в дочернем компоненте, которая увеличивала бы и уменьшала целое число (состояние), управляемое в родительском компоненте. Что тогда делать?
Взаимодействие компонентов представлено в двух формах: поток данных от родителя к дочернему компоненту и поток данных от ребенка к родителю. Мы уже видели, как осуществляется поток от родителя к ребенку с использованием props.
Для успешного достижения передачи данных от ребенка к родителю в react, мы используем обработчики, переданные дочернему компоненту через родительский в качестве props. Родитель знает, что такое действие может произойти у ребенка, поэтому он устанавливает обработчик. Это больше похоже на события:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
var CounterDisplay = React.createClass({
render: function(){
// Вызываем обработчик props после запуска событий
return <div>
<div>{this.props.counterProp}</div>
<button onClick={this.props.incrementCounter}>+</button>
<button onClick={this.props.decrementCounter}>—</button>
</div>
}
})
var Counter = React.createClass({
getInitialState: function() {
return {
counter: 0
};
},
handleIncrement(){
// Обновляем счетчик состояния
this.setState({counter : this.state.counter+1});
},
handleDecrement(){
// Обновляем счетчик состояния
this.setState({counter : this.state.counter—1});
},
render: function() {
// Передаем обработчики компоненту CounterDisplay
return <div>
<h2>{this.props.name}</h2>
<CounterDisplay
counterProp={this.state.counter}
incrementCounter={this.handleIncrement}
decrementCounter={this.handleDecrement}></CounterDisplay>
</div>;
}
});
ReactDOM.render(
<Counter name={‘Counter’} />,
document.getElementById(‘container’)
);
|
У компонента CounterDisplay есть событие click. Обработчик, в свою очередь, обновляет состояние с помощью метода this.setState() и счетчик отображает обновленные свойства.
# Компонент со значением по умолчанию
Не только состояния имеют возможность пользоваться начальными значениями с методом getInitialState. При необходимости вы также можете установить значения по умолчанию для props, которые будут использоваться при загрузке компонента. Для этого вы можете воспользоваться методом getDefaultProps:
1
2
3
4
5
|
getDefaultProps: function() {
return {
name: ‘Counter’
};
},
|
Это очень пригодится для настройки значений по умолчанию в приложении.
# Валидация свойств компонентов
Одна из хорошей вещей в react компонентах, которую разработчики выделяют это юзабилити. Вы можете убрать любой компонент в приложении, чтобы сделать то, что намеревались сделать при условии соблюдения правила. Как же я использую правила при создании своих компонентов повторного использования? Ответ на этот вопрос —валидация свойств компонентов
Валидация помогает вам чувствовать себя уверенным в том, что данные, поступающие в ваш компонент структурированы так, как вы ожидаете.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[code]
var CounterDisplay = React.createClass({
render: function(){
// Вызываем обработчик props после запуска событий
return <div>
<div>{this.props.counterProp}</div>
<br />
<button onClick={this.props.incrementCounter}>+</button>
<button onClick={this.props.decrementCounter}>—</button>
</div>
},
// Проверка настроек для каждого props
propTypes: {
// Должно быть число
counterProp: React.PropTypes.number.isRequired,
// Должны быть функции
incrementCounter: React.PropTypes.func.isRequired,
decrementCounter: React.PropTypes.func.isRequired
}
})
[/code]
|
Если все, что вам нужно, это проверить тип и существует ли он или нет, можете не включать isRequired:
1
2
3
4
5
6
|
propTypes: {
// Должно быть число
counterProp: React.PropTypes.number,
// Должны быть функции
incrementCounter: React.PropTypes.func,
decrementCounter: React.PropTypes.func }
|
# Компонент Класс (ES6)
React.createClass это не только единственный возможный способ создать валидный компонент React. С ЕS6 (что очень здорово), мы можем использовать классы, чтобы создавать react компоненты. Это означает, что вместо объекта в качестве аргумента со свойствами, мы используем наследование класса от React.Component для определения поведения:
1
2
3
4
5
6
7
8
9
10
|
// Расширение React.Component
class Comment extends React.Component {
// Render method now a class member rather than
// свойство объекта
render(){
return <h1>{this.props.name}</h1>;
}
}
React.render(<Comment name={‘Comment’}/>, document.getElementById(‘container’));
|
Имя компонента это имя класса и класс расширяется от React.Component чтобы унаследовать его функциональные возможности.
Установка состояний с классами
Если вы решили идти по пути классов, то будьте готовы к изменениям. Изменения незначительные, например в установке начальных состояний:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Comment extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
render(){
return <h1>{this.props.name}</h1>;
}
}
React.render(<Comment name={‘Comment’}/>, document.getElementById(‘container’));
|
Начальное состояние сейчас находится в конструкторе класса вместо использования getInitialState. Важно всегда передавать props обратно родительскому классу с помощью super (props).
PROPS ПО УМОЛЧАНИЮ И ВАЛИДАЦИЯ С ИСПОЛЬЗОВАНИЕМ КЛАССОМ
Свойства по умолчанию и проверка свойства отличаются также как и параметр исходного состояния. Мы рассматриваем методы, отвечающие за выполнение этих действий, такие как статические члены класса компонента, который они:
1
2
3
4
5
6
7
8
9
10
11
|
// Валидация
Comment.propTypes = {
counterProp: React.PropTypes.number.isRequired,
incrementCounter: React.PropTypes.func.isRequired,
decrementCounter: React.PropTypes.func.isRequired
};
// По умолчанию
Comment.defaultProps = {
name: ‘Counter’
};
|
Есть еще несколько незначительных различий, но вы должны обратить внимание на то, что выше. А об остальных различиях вы можете почитать в статье Тодда.
# Бесструктурные компоненты
Когда компоненту не нужно иметь дело с состояниями, то не следует использовать класс для определения компонента. Вы можете использовать только функции, если все, что требуется в компоненте это props.
1
2
3
4
5
6
7
8
|
function CommentDisplay(props) {
return <div>
<div>{props.counterProp}</div>
<br />
<button onClick={props.incrementCounter}>+</button>
<button onClick={props.decrementCounter}>—</button>
</div>
}
|
Это проще чем вы думаете!!!
# Заключение
Темы, которые мы рассмотрели сегодня, это то, что приведет вас к настоящей разработке приложения на React.
Управление состоянием в react может показаться сложным, и именно поэтому , существуют такие инструменты, как Redux. Со временем, мы выложим туториалы о том, как управлять состоянием приложения используя Redux.
Источник: scotch.io