-
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
--- | ||
|
||
Ранее мы рассмотрели как создавать компоненты для отображения данных и отдельно рассмотрели как обрабатывать действия пользователя. Теперь давайте разберемся как можно собирать наши компоненты в одно приложение. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. мы рассмотрели <...> и отдельно рассмотрели — надо упростить :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. как можно собирать -> как собрать |
||
|
||
## Главная причина: разделение ответственностей | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Главная причина -> Цель |
||
|
||
Создавая всё больше модульных компонентов, вы тем самым получаете столько же преимуществ, сколько получили бы при использовании функций и классов. В разных частях вашего приложения вы можете *выделить разные ответственности*, однако всё это приведет к тому, что вы просто будете создавать новые компоненты. Создавая в своем приложении такую библиотеку компонентов, вы тем самым создаете свои интерфейсы тем способом, который вам больше подходит. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Создавая всё больше" — такого нет в оригинальном тексте. "components that reuse other components with well-defined interfaces" потерялось — такого нет в переводе. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Попробуйте прочитать этот параграф на русском, не подглядывая в английский. Он совершенно непонятен. Нужно его полностью переписать. "Создавая в своем приложении такую библиотеку компонентов, вы тем самым создаете свои интерфейсы тем способом, который вам больше подходит" в принципе ничего не значит. |
||
|
||
## Пример посложнее | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Composition = композиция, не "посложнее" |
||
|
||
Давайте создадим компонент 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') | ||
); | ||
``` | ||
|
||
## Владение | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Наверное лучше будет "принадлежность". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Тут я не уверен. Может "владение" и ок. Надо исправить предложения ниже и посмотреть еще раз. |
||
|
||
В этом примере объект `Avatar` *владеет* объектами `PagePic` и `PageLink`. В React **владельцем считается тот компонент, который устанавливает значения `props` другим компонентам**. Более формально это звучит так, если компонент `X` создается в методе `render()` компонента `Y`, то говорят, что `X` *подчиняется* `Y`. Как обсуждалось ранее, компонент не может менять значения своих `props`, — они всегда содержат те значения, которые установил компонент-владелец. Соблюдение этого правила позволит избежать ошибок при работе с интерфейсом. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instance = экземпляр, не "объект" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Более формально это звучит так, если ... то говорят ..." — так не пишут. Достаточно "другими словами". Постарайтесь написать так, чтобы это читалось естественно. |
||
|
||
Стоит отметить различие между отношениями владелец-подчиненный и родитель-потомок. Отношение владелец-подчиненный возможно только в 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 проводит согласование потомков компонента в той последовательности, в которой они были отрисованы ранее. Предположим, при повторной отрисовке был сгенерирован следующий код: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. пропущена запятая после слова "процесс" |
||
|
||
```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` при повторной отрисовке могут возникнуть проблемы. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пропущена запятая после слова "компонентов" |
||
|
||
Чтобы таких проблем не было, дочерние элементы можно прятать, а не удалять: | ||
|
||
```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). | ||
|
||
## Передача данных | ||
|
||
В реакте передача данных от компонета-владельца к подчиненным компонентам происходит через `props`. Это эффективный однонаправленный способ передачи данных: компоненты-владельцы могут устанавливать значения `props` у подчиненных компонентов, используя свои `props` или `state`. | ||
|
||
## Замечание о производительности | ||
|
||
Вы можете подумать, что изменение данных будет слишком дорогостоящей операцией, если подчиненных узлов будет много. Хорошо что JavaScript работает достаточно быстро и методы `render()` обычно просты, так что приложения тоже будут выполняться также быстро. Чаще всего самым узким местом в программе будут операции по изменению DOM, а не работа JS. Отслеживая происходящие в DOM изменения, React заметно сокращает время на выполнение этих операций. | ||
|
||
Однако, вам может понадобиться полный контроль над происходящим. В этом случае, переопределите метод `shouldComponentUpdate()` так, чтобы он возвращал false, этим вы полностью отключите обработку поддеревьев React. Более подробно об этом читайте в [справочнике React](/react/docs/component-specs.html). | ||
|
||
> Замечание: | ||
> | ||
> Если метод `shouldComponentUpdate()` вернет false в тот момент, когда данные только что изменились, React не станет обновлять интерфейс. Вы должны четко понимать что делаете, чтобы пользоваться этим приемом. Используйте его только когда заметите проблему производительности. Всё-таки, JavaScript работает гораздо быстрее чем, происходят изменения в DOM. |
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
.