Що таке HOC?
Коротке визначення
Higher-Order Component (HOC) - це функція, яка приймає компонент як аргумент і повертає новий компонент, додаючи йому додаткову поведінку або дані.
Тобто:
HOC = функція, що обгортає компонент, щоб "розширити" його функціональність.
Приклад в один рядок
const EnhancedComponent = withSomething(BaseComponent);Тут:
BaseComponent- твій звичайний компонент;withSomething- функція HOC;EnhancedComponent- новий компонент з доданою логікою.
Приклад 1. Найпростіший HOC - логування рендеру
function withLogger(WrappedComponent) {
return function Enhanced(props) {
console.log(`Рендериться компонент: ${WrappedComponent.name}`);
return <WrappedComponent {...props} />;
};
}Використання:
function Hello({ name }) {
return <h1>Hello, {name}</h1>;
}
const HelloWithLogger = withLogger(Hello);
// ...
<HelloWithLogger name="Alex" />;Що відбувається:
withLoggerповертає новий компонент;- при кожному рендері в консоль виводиться ім'я компонента;
- оригінальний компонент (
Hello) отримує всіpropsбез змін.
Приклад 2. HOC, що додає дані
function withUser(WrappedComponent) {
return function Enhanced(props) {
const user = { name: "Alex", role: "admin" };
return <WrappedComponent {...props} user={user} />;
};
}
function Profile({ user }) {
return <p>Користувач: {user.name}</p>;
}
const ProfileWithUser = withUser(Profile);Тепер ProfileWithUser - це версія Profile,
яка завжди отримує user через props,
без потреби дублювати цю логіку в кожному компоненті.
Приклад 3. Додавання стану або ефектів
function withWindowWidth(WrappedComponent) {
return function Enhanced(props) {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return <WrappedComponent {...props} width={width} />;
};
}
function Info({ width }) {
return <p>Ширина вікна: {width}px</p>;
}
const InfoWithWidth = withWindowWidth(Info);Тепер InfoWithWidth автоматично отримує поточну ширину вікна,
і компоненту Info не потрібно знати, як це обчислюється.
Важливі принципи HOC
- Не змінюй вихідний компонент HOC має обгортати, а не мутувати компонент. Погано:
WrappedComponent.prototype.newMethod = () => {}Добре:
return function Enhanced() { return <WrappedComponent />; };- Передавай
propsдалі Завжди прокидуй...props, щоб не втрачати передані властивості:
return <WrappedComponent {...props} />;- Зберігай читабельне ім'я компонента У HOC часто роблять:
Enhanced.displayName = `withLogger(${WrappedComponent.displayName || WrappedComponent.name})`;- Не зловживай вкладеністю Багато HOC поспіль створюють "піраміду":
withTheme(withAuth(withRouter(withLogger(App))))Це погіршує читабельність і дебаг.
Приклад 4. Реальний кейс - HOC в Redux
Найвідоміший HOC - connect() з React Redux:
import { connect } from "react-redux";
function Profile({ user }) {
return <p>Hello, {user.name}</p>;
}
const mapState = (state) => ({ user: state.user });
export default connect(mapState)(Profile);Тут connect:
- підписує компонент на Redux-store;
- передає стан у вигляді
props; - повертає новий компонент, що обгортає
Profile.
Коли використовувати HOC
Коли потрібно повторно використати логіку між компонентами:
- авторизація / доступ (
withAuth) - обробка помилок (
withErrorBoundary) - завантаження даних (
withDataFetch) - вимірювання розміру вікна, позиції миші тощо
Не варто використовувати:
- якщо те саме можна виразити через хуки (
useUser,useWindowWidthтощо); - коли виникає "драбинка" вкладених компонентів.
Сучасна альтернатива: Хуки
Після появи хуків (React 16.8) HOC майже завжди замінюються хуками:
// Замість HOC
const ProfileWithUser = withUser(Profile);
// Можна просто:
function Profile() {
const user = useUser();
return <p>{user.name}</p>;
}Хуки простіші, читабельніші і не створюють вкладених структур.
Підсумок
| Що | Опис |
|---|---|
| HOC | Функція, яка приймає компонент і повертає новий |
| Мета | Додати компоненту спільну логіку або дані |
| Приклад | withLogger(Component), connect(mapState)(Component) |
| Не робить | Змін всередині вихідного компонента |
| Сучасна альтернатива | Кастомні хуки (useAuth, useTheme, useUser) |
Головна думка:
Higher-Order Component - це "обгортка", яка розширює можливості компонента, не змінюючи його вихідний код. Сьогодні HOC дедалі частіше замінюють хуками, але принцип "обгортання" лишився фундаментальним для React.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.