При использовании React вы когда-нибудь видели много кода в файле, включая чтение и обработку данных приложения, и отображение данных, и каждый компонент нельзя использовать повторно.
Давайте сначала рассмотрим пример компонента контейнера и компонента представления вместе.
class TodoList extends React.Component{
constructor(props){
super(props);
this.state ={
todos:[]
}
this.fetchData = this.fetchData.bind(this);
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch('/api/todos').then(data =>{
this.setState({
todos:data
})
})
}
render(){
const {todos} = this.state;
return (<div>
<ul>
{todos.map((item,index)=>{
return <li key={item.id}>{item.name}</li>
})}
</ul>
</div>)
}
}
Вы можете видеть, что нет возможности повторно использовать этот пример, потому что запрос данных и отображение данных выполняются в одном компоненте.Чтобы добиться повторного использования компонента, нам нужно отделить компонент дисплея от компонента контейнера.
Конкретный код выглядит следующим образом:
//展示组件
class TodoList extends React.Component{
constructor(props){
super(props);
}
render(){
const {todos} = this.props;
return (<div>
<ul>
{todos.map((item,index)=>{
return <li key={item.id}>{item.name}</li>
})}
</ul>
</div>)
}
//容器组件
class TodoListContainer extends React.Component{
constructor(props){
super(props);
this.state = {
todos:[]
}
this.fetchData = this.fetchData.bind(this);
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch('/api/todos').then(data =>{
this.setState({
todos:data
})
})
}
render(){
return (<div>
<TodoList todos={this.state.todos} />
</div>)
}
}
Когда мы разделим компоненты на компоненты-контейнеры и компоненты представления, вы обнаружите, что их можно легко использовать повторно.
Презентационный компонент
- Обратите внимание на эффект отображения (внешний вид) страницы
- Внутренние компоненты и контейнеры могут включать компоненты отображения, обычно содержащие некоторые собственные теги DOM и стиль (стиль).
- Обычно разрешается включать другие компоненты через this.props.children.
- Нет никаких зависимостей от других частей приложения, таких как операции или хранилища Flux.
- Неважно, как данные загружаются и изменяются.
- Вы можете получать данные и выполнять операции обратного вызова только через реквизиты.
- Редко имеет собственное состояние, даже если оно есть, оно используется для отображения состояния пользовательского интерфейса.
- Будет написан как функциональный компонент, если компонент не нуждается в собственном состоянии, жизненном цикле или некоторой оптимизации производительности.
Пример:
Страница, Заголовок, Боковая панель, Информация о пользователе, Список
Компонент контейнера
- Сосредоточьтесь на том, как работает приложение
- Inside может содержать компоненты-контейнеры и компоненты представления, но обычно не имеет собственной разметки DOM, за исключением некоторых разделов-оболочек, и никогда не имеет стилей.
- Предоставляйте данные и поведение другим презентационным или контейнерным компонентам.
- Вызывайте операции Flux и предоставляйте их в качестве обратных вызовов компонентам представления.
- имеют тенденцию к сохранению состояния, поскольку они, как правило, действуют как источники данных
- Обычно создается с использованием компонентов более высокого порядка, таких как connect() React Redux, createContainer() Relay или Container.create() Flux Utils, а не пишется вручную.
Example:
UserPage, FollowersSidebar, StoryContainer, FollowedUserList
преимущество
- Лучшее разделение компонентов представления и контейнера для лучшего понимания приложения и пользовательского интерфейса.
- Компоненты представления с высокой степенью повторного использования могут использоваться для нескольких различных источников данных.
- Презентационные компоненты — это ваши палитры, и вы можете поместить их на отдельные страницы и позволить дизайнерам настраивать пользовательский интерфейс, не затрагивая приложение.
- Это заставляет вас извлекать «компоненты макета», такие как боковые панели, страницы, контекстные меню и т. д., и использовать this.props.children вместо дублирования одной и той же разметки и макета в нескольких компонентах-контейнерах.
При введении в сборку контейнера
Я предлагаю вам начать создавать компоненты только с компонентами представления и в конечном итоге понять, что вы передаете много свойств промежуточным компонентам, которые вообще не используют свойства, которые они получают, а просто передают их вниз. И когда этим подкомпонентам нужно больше данных, нужно переконфигурировать эти промежуточные компоненты. В это время вам нужно представить компонент контейнера. С компонентами-контейнерами вы можете передавать данные и поведение листовым компонентам через свойства, не беспокоясь о каких-то несвязанных промежуточных компонентах.
Это процесс рефакторинга, так что это лучше, чем делать все правильно с первого раза. когда вы попробуете этот режим. У вас будет интуитивное представление о том, когда его следует извлечь как компонент контейнера. как если бы вы знали, когда извлечь функцию
дихотомия
Важно, чтобы вы понимали, что разница между компонентами-контейнерами и компонентами представления — не техническая разница, а разница в назначении.
Напротив, вот несколько связанных (но разных) технических различий:
-
С состоянием и без гражданства:
Компоненты-контейнеры, как правило, имеют состояние, а презентационные компоненты, как правило, не имеют состояния.Это не жесткое и быстрое правило, поскольку и контейнер, и компоненты представления могут иметь состояние.
-
Классы [Classes] и функции [Functions]:
Компоненты могут быть объявлены как классы или функции.Функциональные компоненты определить просто, но в них отсутствуют некоторые функции, которые в настоящее время используются только для классов. Хотя функциональные компоненты имеют много ограничений, они все еще используются до сих пор, потому что функциональные компоненты просты для понимания, и рекомендуется использовать функциональные компоненты, когда они не требуют своего собственного состояния, ловушек жизненного цикла или оптимизации производительности. Они применяются только к компонентам класса.
//我们将上边的展示组件改写成函数组件可以如下
function TodoList(props){
return (<div>
<ul>
{props.todos.map((item,index)=>{
return <li key={item.id}>{item.name}</li>
})}
</ul>
</div>)
}
Многие люди могут не знать разницы между функциональными компонентами и классовыми компонентами, вы можете зайти на официальный сайт React, чтобы посмотретьФункциональные компоненты и компоненты класса
-
Чистый 【Чистый】 и Нечистый 【Нечистый】:
Чистый: выводит то, что вводится, и не будет вносить в него соответствующие изменения. Могут быть определены как класс или функция, могут быть без сохранения состояния или с сохранением состояния. Еще одним важным аспектом чистых компонентов является то, что они не зависят от глубоких изменений свойств или состояния, поэтому производительность их рендеринга можно контролировать с помощью хука shouldComponentUpdate(). по сравнению с оптимизацией, в настоящее время только классы могут определять метод shouldComponentUpdate().
И компоненты отображения, и компоненты-контейнеры будут иметь вышеуказанные дихотомические характеристики. На мой взгляд, презентационные компоненты, как правило, являются чистыми функциями без состояния, в то время как контейнерные компоненты, как правило, являются чистыми классами с состоянием, просто личное мнение, а не правило.
Когда это не важно или трудно различить, не принимайте разделение компонентов контейнера и компонентов представления как догму, Если вы не уверены, является ли компонент компонентом-контейнером или презентационным компонентом, пока не разделяйте его и пишите как презентационный компонент.
Источник перевода: https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0