Що робить патерн "Render Props"?
Визначення
Render Props - це патерн, при якому компонент отримує функцію як пропс, і викликає її всередині себе, передаючи потрібні дані чи поведінку.
Іншими словами:
Компонент сам не знає, що саме рендерити - він просто ділиться логікою, а зовнішній код вирішує, як це відобразити.
Сенс патерна
Render Props дозволяє зробити логіку, придатну для повторного використання (наприклад, обробку стану, подій, API-запитів тощо) і винести її в окремий компонент, не прив'язуючись жорстко до UI.
Приклад: відстеження позиції курсора
Без Render Props (усе в одному компоненті)
function MouseTracker() {
const [pos, setPos] = useState({ x: 0, y: 0 });
return (
<div
onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}
style={{ height: 200, background: '#eee' }}
>
<p>Координати: {pos.x}, {pos.y}</p>
</div>
);
}Працює, але UI і логіка пов'язані. Ми не можемо перевикористати "логіку трекінгу миші" в іншому місці.
З Render Props
function Mouse({ children }) {
const [pos, setPos] = useState({ x: 0, y: 0 });
return (
<div
onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}
style={{ height: 200 }}
>
{children(pos)} {/* ← функція-рендер */}
</div>
);
}
// Використовуємо
function App() {
return (
<Mouse>
{(pos) => <p>Позиція курсора: {pos.x}, {pos.y}</p>}
</Mouse>
);
}Тут
<Mouse>керує логікою, а компонент, що його використовує, сам вирішує, як відрисувати результат.
Як це працює під капотом
- Компонент отримує функцію через props (наприклад,
childrenабоrender) - Всередині компонента ця функція викликається з потрібними даними
- React рендерить те, що поверне ця функція
{props.render(data)}або
{props.children(state)}Приклад: компонент з Render Props для стану
function Toggle({ children }) {
const [on, setOn] = useState(false);
const toggle = () => setOn(!on);
return children({ on, toggle });
}
// Використовуємо
<Toggle>
{({ on, toggle }) => (
<div>
<button onClick={toggle}>{on ? "Викл" : "Увімк"}</button>
{on && <p>Секретний текст</p>}
</div>
)}
</Toggle>Тут
<Toggle>відповідає за логіку, а розмітку визначає користувач через render prop.
Навіщо потрібен Render Props
| Проблема | Як вирішує Render Props |
|---|---|
| Хочеш перевикористати логіку, але не UI | Виносиш її в компонент, а UI передаєш функцією |
| Потрібно розділити дані і представлення | Дані приходять через render-функцію |
| Не хочеш використовувати HOC | Render Props - альтернатива HOC |
| Потрібен компонент, що "ділиться станом" | Передає state і actions у функцію |
Коли використовувати
Підходить для:
- логіки, що повторюється (hover, toggle, fetch, resize, mouse position, scroll)
- стану (відкрито/закрито, вибрано/не вибрано)
- загальних "поведінкових" компонентів
Не підходить, якщо:
- код стає сильно вкладеним;
- достатньо просто винести логіку в кастомний хук (в епоху React Hooks).
Сучасна альтернатива Render Props - хуки
З появою React Hooks патерн Render Props майже повністю замінили кастомні хуки, оскільки вони простіші і менш вкладені.
Приклад: той самий Toggle, але з хуком
function useToggle(initial = false) {
const [on, setOn] = useState(initial);
const toggle = () => setOn(!on);
return { on, toggle };
}
function App() {
const { on, toggle } = useToggle();
return (
<>
<button onClick={toggle}>{on ? "ON" : "OFF"}</button>
{on && <p>Секретний текст</p>}
</>
);
}Хук робить те саме, що раніше робив компонент з Render Props, але без вкладеності і з чистішою структурою.
Підсумок
| Що | Опис |
|---|---|
| Ідея | Компонент приймає функцію, яку викликає для рендеру |
| Мета | Розділити логіку і представлення |
| Як працює | props.children(state) або props.render(data) |
| Переваги | Перевикористовуваність логіки, гнучкість UI |
| Сучасна альтернатива | Кастомні хуки |
Головна думка: Render Props - це спосіб ділитися поведінкою, а не розміткою. Компонент віддає назовні стан і події, а зовнішній код вирішує, як їх візуалізувати.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.