-
Notifications
You must be signed in to change notification settings - Fork 47.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create 04-multiple-components.ru-RU.md #6706
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
--- | ||
id: multiple-components | ||
title: Составные компоненты | ||
permalink: multiple-components-ru-RU.html | ||
prev: interactivity-and-dynamic-uis-ru-RU.html | ||
next: reusable-components.html | ||
--- | ||
|
||
Мы разобрались как создавать компоненты для отображения данных и подробно рассмотрели как происходит обработка действий пользователя. Теперь давайте узнаем как собирать компоненты в одно целое. | ||
|
||
## Главная цель: разделение ответственностей | ||
|
||
Создавая новые модульные компоненты, используя уже готовые компоненты с хорошо продуманными интерфейсами, вы получаете столько же преимуществ, сколько получили бы при использовании обычных функций и классов. Создание новых компонентов приводит к тому что вы объединяете их по ответственностям, где каждый компонент относится к своему типу задач. Создавая в приложении собственную библиотеку компонентов, вы будете создавать свои интерфейсы тем способом, который лучше всего вам подходит. | ||
|
||
## Пример составного компонента | ||
|
||
Давайте создадим компонент Avatar, который будет выводить фото и имя пользователя со страницы в Facebook. Для этого воспользуемся Facebook Graph API. | ||
|
||
```javascript | ||
var Avatar = React.createClass({ | ||
render: function() { | ||
return ( | ||
<div> | ||
<PagePic pagename={this.props.pagename} /> | ||
<PageLink pagename={this.props.pagename} /> | ||
</div> | ||
); | ||
} | ||
}); | ||
|
||
var PagePic = React.createClass({ | ||
render: function() { | ||
return ( | ||
<img src={'https://graph.facebook.com/' + this.props.pagename + '/picture'} /> | ||
); | ||
} | ||
}); | ||
|
||
var PageLink = React.createClass({ | ||
render: function() { | ||
return ( | ||
<a href={'https://www.facebook.com/' + this.props.pagename}> | ||
{this.props.pagename} | ||
</a> | ||
); | ||
} | ||
}); | ||
|
||
ReactDOM.render( | ||
<Avatar pagename="Engineering" />, | ||
document.getElementById('example') | ||
); | ||
``` | ||
|
||
## Принадлежность компонентов | ||
|
||
В этом примере экземпляру `Avatar` *принадлежат* экземпляры `PagePic` и `PageLink`. В React **владельцем считается тот компонент, который устанавливает значения `props` другим компонентам**. Другими словами, если компонент `X` создается в методе `render()` компонента `Y`, то говорят, что `X` *принадлежит* `Y`. Компонент не может менять значения своих `props`, — они всегда содержат те значения, которые установил ему компонент-владелец. Следование этому правилу позволит избежать ошибок при работе с интерфейсом. | ||
|
||
В отношениях владелец-подчиненный и родитель-потомок есть важное различие. Отношение владелец-подчиненный возможно только в React, а отношение родитель-потомок вам известно из структуры DOM-дерева. В нашем примере `Avatar` будет владельцем экземпляров `div`, `PagePic` и `PageLink`, а `div`, в свою очередь, будет **родителем** (но не владельцем) элементов `PagePic` и `PageLink`. | ||
|
||
## Потомки | ||
|
||
Когда вы создаете экземпляр компонента React, вы можете дополнять его другими React-компонентами или выражениями на JavaScript внутри открывающего и закрывающего тегов вот так: | ||
|
||
```javascript | ||
<Parent><Child /></Parent> | ||
``` | ||
|
||
`Родитель` может обращаться к своим потомкам через свойство `this.props.children`. **`this.props.children` это специальная структура данных:** используйте [вспомогательные методы React.Children](/react/docs/top-level-api.html#react.children), чтобы работать с ней. | ||
|
||
### Согласование потомков | ||
|
||
**Согласование - процесс, с помощью которого React обновляет DOM во время отрисовки интерфейса.** React проводит согласование потомков компонента в той последовательности, в которой они были отрисованы ранее. Предположим, при повторной отрисовке был сгенерирован следующий код: | ||
|
||
```html | ||
// Отрисовка № 1 | ||
<Card> | ||
<p>Paragraph 1</p> | ||
<p>Paragraph 2</p> | ||
</Card> | ||
// Отрисовка № 2 | ||
<Card> | ||
<p>Paragraph 2</p> | ||
</Card> | ||
``` | ||
|
||
Можно предположить, что будет удален узел `<p>Paragraph 1</p>`. Однако, React выстроит DOM по-своему; он изменит текст у первого потомка, а второго потомка удалит. React проводит согласование в соответствии с *расположением* дочерних узлов. | ||
|
||
### Потомки с состоянием | ||
|
||
Для большинства компонентов такой проблемы нет. Однако, у тех компонентов, которые хранят данные в `this.state` при повторной отрисовке могут возникнуть проблемы. | ||
|
||
Чтобы их избежать, дочерние элементы, вместо того чтобы удалить, иногда прячут: | ||
|
||
```html | ||
// Отрисовка № 1 | ||
<Card> | ||
<p>Paragraph 1</p> | ||
<p>Paragraph 2</p> | ||
</Card> | ||
// Отрисовка № 2 | ||
<Card> | ||
<p style={{'{{'}}display: 'none'}}>Paragraph 1</p> | ||
<p>Paragraph 2</p> | ||
</Card> | ||
``` | ||
|
||
### Динамичные потомки | ||
|
||
Ситуация осложняется, когда потомки перемешиваются между собой (например, при выдаче результатов поиска) или если новые компоненты добавляются в начало списка (как происходит в потоках). Если после каждой отрисовки потомок должен сохранять своё состояние и местоположение, вам надо присвоить ему уникальный идентификатор с помощью атрибута `key`: | ||
|
||
```javascript | ||
render: function() { | ||
var results = this.props.results; | ||
return ( | ||
<ol> | ||
{results.map(function(result) { | ||
return <li key={result.id}>{result.text}</li>; | ||
})} | ||
</ol> | ||
); | ||
} | ||
``` | ||
|
||
Когда React будет проводить согласование потомков с такими ключами, они гарантированно обработаются корректно. | ||
|
||
Этот уникальный ключ должен *всегда* указываться как атрибут компонента, но не как свойство HTML-тега: | ||
|
||
```javascript | ||
// Неверно! | ||
var ListItemWrapper = React.createClass({ | ||
render: function() { | ||
return <li key={this.props.data.id}>{this.props.data.text}</li>; | ||
} | ||
}); | ||
var MyComponent = React.createClass({ | ||
render: function() { | ||
return ( | ||
<ul> | ||
{this.props.results.map(function(result) { | ||
return <ListItemWrapper data={result}/>; | ||
})} | ||
</ul> | ||
); | ||
} | ||
}); | ||
``` | ||
```javascript | ||
// А так правильно :) | ||
var ListItemWrapper = React.createClass({ | ||
render: function() { | ||
return <li>{this.props.data.text}</li>; | ||
} | ||
}); | ||
var MyComponent = React.createClass({ | ||
render: function() { | ||
return ( | ||
<ul> | ||
{this.props.results.map(function(result) { | ||
return <ListItemWrapper key={result.id} data={result}/>; | ||
})} | ||
</ul> | ||
); | ||
} | ||
}); | ||
``` | ||
|
||
Также вы можете добавить идентификаторы потомкам используя объект ReactFragment. Подробнее смотрите [Фрагменты с ключами](create-fragment.html). | ||
|
||
## Передача данных | ||
|
||
В React передача данных от компонета-владельца к подчиненным компонентам происходит через `props`. Это довольно эффективный способ передачи данных: компоненты-владельцы могут устанавливать значения `props` компонентам которые ему принадлежат, используя свои `props` или `state`. | ||
|
||
## Замечание о производительности | ||
|
||
Вы можете подумать, что изменение данных будет слишком дорогостоящей операцией, если подчиненных узлов будет много. Хорошо что JavaScript работает достаточно быстро и методы `render()` обычно просты, так что приложения будут выполняться также быстро. Чаще всего самым узким местом в программе будут операции по изменению DOM, а не работа JS. Отслеживая происходящие в DOM изменения, React заметно сокращает время на выполнение этих операций. | ||
|
||
Однако, вам может понадобиться полный контроль над происходящим. В этом случае, переопределите метод `shouldComponentUpdate()` так, чтобы он возвращал false, этим вы полностью отключите обработку поддеревьев React. Более подробно об этом читайте в [справочнике React](/react/docs/component-specs.html). | ||
|
||
> Замечание: | ||
> | ||
> Если метод `shouldComponentUpdate()` вернет false в тот момент, когда данные только что изменились, React не станет обновлять интерфейс. Вы должны четко понимать что делаете, чтобы пользоваться этим приемом. Используйте его только когда заметите проблему производительности. Всё-таки, JavaScript работает гораздо быстрее чем, происходят изменения в DOM. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We’d also need to change
03-interactivity-and-dynamic-uis.ru-RU.md
to point to this page as itsnext
.