Поиск по сайту:

Что такое презентационные и контейнерные компоненты в React?


React имеет компонентную архитектуру, которая побуждает вас разбивать кодовую базу на повторно используемые единицы функциональности. Однако не все компоненты одинаковы. Давайте посмотрим на различия между двумя распространенными типами компонентов: Presentational и Container (также известными как «Stateful»).

Есть ли государство?

Для начала следует подчеркнуть, что эти термины не относятся к какой-либо конкретной функции React. Они описывают стиль написания компонентов React, который помогает поддерживать модульность и разделять задачи. Существование двух типов компонентов является результатом выбора, сделанного в вашей кодовой базе.

Есть только один отличительный фактор: компоненты-контейнеры имеют состояние, а компоненты представления — нет. На практике это означает, что компонент-контейнер всегда вызывает метод React setState(). Компонент представления никогда не будет использовать состояние.

Глядя на примеры

Вот простой презентационный компонент:

import React from "react";
 
class Presentational extends React.Component {
 
    render() {
        return <h1>{this.props.title}</h1>;
    }
 
}
 
export default Presentational;

Компонент предельно прост. Он отображает один тег h1, который отображает текст, переданный в компонент через его свойство title. Давайте теперь посмотрим на компонент контейнера с отслеживанием состояния:

import React from "react";
 
class Container extends React.Component {
 
    constructor(props) {
        super(props);
 
        this.state = {
 
            time: (new Date()).toString()
 
        };
 
    }
 
 
    componentDidMount() {
        setInterval(() => {
            this.setState({time: (new Date()).toString()});
        }, 1000);
    }
 
 
    render() {
        return <h1>{this.state.time}</h1>;
    }
 
}
 
export default Container;

Метод render компонента-контейнера почти идентичен тому, что используется в презентационном компоненте. Разница в том, что компонент-контейнер получает текст изнутри себя, вместо того, чтобы полагаться на внешнее значение, переданное в качестве свойства.

Каждую секунду компонент-контейнер вызывает setState() для обновления ключа time в его состоянии. Это заставляет React повторно отображать компонент и отображать новое время. Наш контейнер имеет собственное состояние.

Характеристики каждого типа

Как в презентационных, так и в контейнерных компонентах возникает несколько уникальных характеристик. Прежде всего, если рассматривать презентационные компоненты, большая часть их кода, скорее всего, находится в методе render. В них будет очень мало логики, поскольку их поведение определяется внешним миром.

Презентационные компоненты пребывают в блаженном неведении относительно того, откуда берутся их данные. Они не знают, когда (и изменится ли) это. Некоторые примеры могут даже не принимать реквизит. Вот декоративный элемент, который просто отображает определенный файл изображения:

<code>export () => <img src="/logo.png" /></code>

Компоненты-контейнеры во многом противоположны своим презентационным аналогам. Обычно вы обнаружите, что большая часть логики вашего сайта находится внутри компонента-контейнера. Метод render может быть сравнительно коротким, так как вы будете тратить гораздо больше строк на получение данных из внешних источников, преобразование их в соответствии с вашими потребностями и последующее сохранение их в состояние.

Метод render компонента-контейнера может состоять из одной строки, которая отображает презентационный компонент. Теперь у вас есть четкое разделение задач, при этом оба компонента играют четкую роль, которая полностью уважает друг друга. Компонент-контейнер является источником данных; презентационный компонент помещает его на экран.

Вот как это выглядит на практике:

import React from "react";
 
const View = ({title, body}) => (
    <div>
        <h1>{title}</h1>
        <p>{body}</p>
    </div>
);
 
class BlogPostComponent extends React.Component {
 
    constructor(props) {
        super(props);
 
        this.state = {
 
            blog: null
 
        };
 
    }
 
 
    componentDidMount() {
        fetch("/blog-post.json")
            .then(response => response.json());
            .then(blog => this.setState({blog}));
    }
 
 
    render() {
        return (
            <View
                title={this.state.blog.headline}
                body={this.state.blog.content} />
        );
    }
 
}}

BlogPostComponent — наш компонент-контейнер. Загружает пост по сети. Затем данные передаются компоненту View для рендеринга. View не важно, откуда он берет данные — в будущем мы могли бы повторно использовать его для отображения сообщений, полученных из стороннего API, такого как Facebook или Twitter.

Компоненты-контейнеры называются так потому, что они, как правило, инкапсулируют целые функциональные области вашего приложения. Они заставляют ваш проект работать и представляют серверные системы приложения.

В реальной кодовой базе на BlogPostComponent возлагается еще большая ответственность. Ему нужно будет отслеживать, загрузился ли пост, и обрабатывать ошибки во время выборки по сети. Следовательно, метод render может включать некоторую базовую логику для изменения того, что отображается — либо сообщение об ошибке, индикатор выполнения, либо наш презентационный компонент View. Презентационные компоненты никогда не несут большей ответственности, чем рендеринг определенного раздела пользовательского интерфейса в DOM.

Преимущества разделения презентационных и контейнерных компонентов

Использование этого шаблона поможет вам организовать кодовую базу и не даст компонентам стать слишком громоздкими. Хотя это не жесткое правило, тщательное разделение двух типов повышает удобство сопровождения по мере роста количества компонентов вашего проекта.

Старайтесь искать возможности для рефакторинга по мере роста метода render компонента-контейнера. Вероятно, вы могли бы взять большую часть его содержимого и разделить на новый презентационный компонент. Это упрощает повторное использование презентационного кода в будущем. В конечном итоге он становится автономным и способен работать независимо от любого конкретного источника данных.

Компоненты с состоянием реже используются повторно. Нетривиальное поведение естественным образом накапливается внутри них, что приводит к зависимости от внешнего мира. Это не означает, что их нельзя использовать повторно — кнопка двухэтапного подтверждения будет содержать внутреннее состояние (чтобы определить, следует ли отображать «Сбросить пароль пользователя» или «Вы уверены?»), но будет также быть развернуты во всей вашей кодовой базе.

Возможно, больше всего намеренное разграничение компонентов Presentional и Container помогает вам понять, где находится состояние вашего приложения. Минимизация количества компонентов с состоянием способствует созданию поддерживаемой кодовой базы и помогает разделять проблемы.

Если вы не можете решить, должен ли компонент сохранять состояние, продолжите кодирование и рефакторинг позже — вероятно, еще слишком рано в жизненном цикле вашего проекта, чтобы знать, где соберется сложность (и, следовательно, состояние).




Все права защищены. © Linux-Console.net • 2019-2024