← Назад к вопросам

Что такое Container?

1.0 Junior🔥 201 комментариев
#Инструменты и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Container компоненты в React

Container (контейнер) - это архитектурный паттерн в React, который разделяет компоненты на две категории: контейнеры (умные компоненты) и presentational компоненты (глупые компоненты). Этот паттерн помогает организовать код, сделать его более переиспользуемым и тестируемым.

Что такое Container?

Container компонент (также называемый "Smart Component" или "Connected Component"):

  • Содержит бизнес-логику и управление состоянием
  • Отвечает за загрузку данных и их обработку
  • Работает с Redux, Context, API и другими внешними источниками
  • Обычно не отображает UI напрямую
  • Передаёт данные и колбэки в Presentational компоненты через props

Presentational компонент ("Dumb Component"):

  • Чистая функция, которая получает данные через props
  • Содержит только логику отображения (rendering logic)
  • Не имеет внешних зависимостей
  • Легко тестировать и переиспользовать
  • Часто содержит локальное состояние для UI (открыт ли модал, фокус и т.п.)

Пример: Container + Presentational

// UserProfileContainer.jsx - CONTAINER компонент
import React, { useState, useEffect } from 'react';
import UserProfile from './UserProfile'; // Presentational компонент

function UserProfileContainer({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Бизнес-логика: загрузка данных
    fetchUser(userId)
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [userId]);

  const handleUpdateUser = (updatedData) => {
    // Обработка обновления пользователя
    updateUser(userId, updatedData)
      .then(data => setUser(data));
  };

  // Container передаёт все необходимые данные и функции
  return (
    <UserProfile
      user={user}
      loading={loading}
      error={error}
      onUpdateUser={handleUpdateUser}
    />
  );
}

export default UserProfileContainer;
// UserProfile.jsx - PRESENTATIONAL компонент
function UserProfile({ user, loading, error, onUpdateUser }) {
  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;
  if (!user) return <div>Пользователь не найден</div>;

  return (
    <div className="user-profile">
      <h1>{user.name}</h1>
      <p>{user.email}</p>
      <button onClick={() => onUpdateUser({ verified: true })}>
        Подтвердить
      </button>
    </div>
  );
}

export default UserProfile;

Преимущества паттерна Container/Presentational

1. Разделение ответственности

  • Container: отвечает за логику и состояние
  • Presentational: отвечает только за отображение
  • Код становится структурированнее и понятнее

2. Переиспользуемость

Презентационный компонент можно использовать в разных местах приложения с разными контейнерами:

// Одном и тот же компонент UserProfile используется в разных контейнерах
<CurrentUserProfileContainer /> // Текущий пользователь
<SearchedUserProfileContainer /> // Найденный пользователь
<AdminUserProfileContainer /> // Админ панель

3. Тестируемость

Презентационные компоненты легко тестировать, так как это чистые функции:

import { render, screen } from '@testing-library/react';
import UserProfile from './UserProfile';

test('отображает информацию пользователя', () => {
  const mockUser = { name: 'John', email: 'john@example.com' };
  render(
    <UserProfile 
      user={mockUser} 
      loading={false} 
      error={null}
      onUpdateUser={jest.fn()}
    />
  );
  
  expect(screen.getByText('John')).toBeInTheDocument();
  expect(screen.getByText('john@example.com')).toBeInTheDocument();
});

4. Упрощение отладки

Вы всегда знаете, где находится логика (в контейнере) и где отображение (в презентационном компоненте).

Современный подход: Hooks + Context вместо паттерна

С появлением React Hooks паттерн Container/Presentational стал менее популярен. Вместо этого используют:

1. Custom Hooks для логики

// useUser.js - кастомный хук (логика)
function useUser(userId) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchUser(userId)
      .then(data => {
        setUser(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [userId]);

  return { user, loading, error };
}

export default useUser;
// UserProfile.jsx - компонент с хуком
import useUser from './useUser';

function UserProfile({ userId }) {
  const { user, loading, error } = useUser(userId);

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;

  return (
    <div className="user-profile">
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

export default UserProfile;

2. Context API для глобального состояния

// Вместо передачи props через множество компонентов,
// используем Context для доступа к данным везде
const UserContext = React.createContext();

function UserProvider({ children, userId }) {
  const { user, loading, error } = useUser(userId);

  return (
    <UserContext.Provider value={{ user, loading, error }}>
      {children}
    </UserContext.Provider>
  );
}

function useUserContext() {
  return React.useContext(UserContext);
}

Когда всё ещё используется Container/Presentational?

  1. Большие проекты с Redux - контейнер подключается к Redux store
  2. Сложные компоненты - когда есть значительное разделение логики и отображения
  3. Легаси код - в старых проектах этот паттерн всё ещё используется
// Container с Redux (пример для старых проектов)
import { connect } from 'react-redux';
import UserProfile from './UserProfile';

const mapStateToProps = (state) => ({
  user: state.user.data,
  loading: state.user.loading
});

const mapDispatchToProps = (dispatch) => ({
  onUpdateUser: (data) => dispatch(updateUser(data))
});

export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);

Вывод

Container компонент - это умный компонент, который содержит всю бизнес-логику, управляет состоянием и данными, а затем передаёт их в presentational компоненты для отображения. Этот паттерн способствует разделению ответственности, переиспользуемости и тестируемости кода.

Однако в современной разработке этот паттерн часто заменяют на Custom Hooks + Context API, которые обеспечивают большую гибкость и меньше boilerplate кода. Тем не менее, понимание концепции контейнеров остаётся важным для работы с React и архитектуре приложений.

Что такое Container? | PrepBro