Що робить "Higher-Order Component (HOC)"?
Визначення
Higher-Order Component (HOC) - це функція, яка приймає компонент і повертає новий компонент, додаючи йому додаткову функціональність.
Можна сказати:
HOC - це «компонент-над-компонентом» (аналог декоратора чи обгортки, що додає поведінку).
Формула HOC
const EnhancedComponent = withSomething(BaseComponent);де
withSomething- це HOC-функція, аBaseComponent- вихідний компонент, якому додається логіка.
Приклад: додамо дані про користувача через HOC
1. Вихідний компонент
function UserProfile({ user }) {
return <p>Привіт, {user.name}!</p>;
}2. HOC, який передає дані в props
function withUser(WrappedComponent) {
return function EnhancedComponent(props) {
const user = { name: 'Tim', age: 25 }; // імітація даних
return <WrappedComponent {...props} user={user} />;
};
}3. Використовуємо
const UserProfileWithUser = withUser(UserProfile);
export default function App() {
return <UserProfileWithUser />;
}Тепер
UserProfileнічого не знає про те, звідки беретьсяuser- HOC додав цю поведінку "ззовні".
Що робить HOC по суті
HOC:
- не змінює вихідний компонент,
- не успадковується від нього,
- а створює новий компонент, який композує старий + нову логіку.
Реальний приклад: connect() з Redux
import { connect } from "react-redux";
function MyComponent({ user }) {
return <div>{user.name}</div>;
}
export default connect(
(state) => ({ user: state.user })
)(MyComponent);Тут
connect()- це класичний HOC, який зв'язує компонент зі стором Redux і прокидає потрібні дані в props.
Приклад додавання поведінки: логування
function withLogger(WrappedComponent) {
return function (props) {
console.log(`Рендериться компонент: ${WrappedComponent.name}`);
return <WrappedComponent {...props} />;
};
}
function Hello({ name }) {
return <h1>Привіт, {name}!</h1>;
}
const HelloWithLogger = withLogger(Hello);Тепер при кожному рендері буде логуватися ім'я компонента.
Правила написання HOC
- HOC - це функція, яка повертає компонент:
const withSomething = (Component) => (props) => <Component {...props} />;- Не змінюй вихідний компонент! -> Створюй новий, обгортаючи старий.
- Передавай усі пропси далі, щоб не "розірвати" ланцюжок:
return <WrappedComponent {...props} extra={data} />;- Зберігай ім'я для зручності відлагодження:
Enhanced.displayName = `withSomething(${WrappedComponent.displayName || WrappedComponent.name})`;Що вирішує HOC
| Проблема | Як вирішує HOC |
|---|---|
| Повторювана логіка в різних компонентах | Обгортає їх спільною поведінкою |
| Підключення до зовнішніх даних | Додає потрібні props (наприклад, з Redux чи контексту) |
| Робота з авторизацією / ролями | Перевіряє доступ і вирішує, чи рендерити компонент |
| Логування, аналітика, обробка помилок | Додає поведінку при рендері |
Мінуси HOC
| Проблема | Опис |
|---|---|
| Вкладеність обгорток | Декілька HOC створюють "шаруватий пиріг" (withAuth(withRouter(withTheme(...)))) |
| Важко відстежувати пропси | HOC може непомітно додавати або перевизначати props |
| Неочевидні залежності | Логіка схована в обгортці |
| Хуки витіснили HOC | У сучасному React майже все вирішується хуками (useUser(), useAuth()) |
Сучасна альтернатива - хуки
Патерн HOC був головним способом переюзання логіки до появи хуків. Тепер те саме робиться простіше:
Було (HOC)
const withUser = (Component) => (props) => {
const user = useUser();
return <Component {...props} user={user} />;
};Стало (Hook)
function Profile() {
const user = useUser();
return <p>{user.name}</p>;
}Хуки дають той самий ефект - "вбудовування логіки" - але без обгортання компонентів.
Підсумок
| Що | Опис |
|---|---|
| Визначення | Функція, яка приймає компонент і повертає новий |
| Ціль | Переюзання логіки без дублювання |
| Принцип | Компонент + обгортка = новий компонент |
| Приклад | connect() з Redux, withRouter() з React Router |
| Альтернатива | Кастомні хуки |
| Аналогія | "Декоратор", що додає можливості |
Головна думка:
HOC - це спосіб "надбудувати" поведінку над компонентом, не чіпаючи його вихідний код. Він був попередником сучасних хуків, і досі використовується, коли потрібна обгортка "на рівні компонента", а не "всередині нього".
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.