Render Props (рендер-пропсы) — это паттерн в React, при котором компонент принимает функцию (обычно в пропсе render
или children
), которая возвращает React-элементы. Этот компонент затем вызывает эту функцию, передавая ей необходимые данные.
"Расскажи мне, что рендерить, и я дам тебе данные для этого"
<DataProvider render={data => (
<h1>Привет, {data.username}</h1>
)}/>
Где:
DataProvider
— компонент с логикойrender
— функция, определяющая как отображать данные<Mouse render={({ x, y }) => (
<p>Курсор на ({x}, {y})</p>
)}/>
<Mouse>
{({ x, y }) => (
<p>Курсор на ({x}, {y})</p>
)}
</Mouse>
<Mouse renderPosition={({ x, y }) => (
<p>Позиция: {x}, {y}</p>
)}/>
class Mouse extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (e) => {
this.setState({ x: e.clientX, y: e.clientY });
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.children(this.state)}
</div>
);
}
}
// Использование
<Mouse>
{({ x, y }) => <div>Позиция: {x}, {y}</div>}
</Mouse>
<Toggle>
{({ on, toggle }) => (
<button onClick={toggle}>
{on ? 'Включено' : 'Выключено'}
</button>
)}
</Toggle>
<Fetch url="/api/user">
{({ loading, error, data }) => {
if (loading) return <Spinner />;
if (error) return <Error message={error} />;
return <Profile data={data} />;
}}
</Fetch>
<ThemeContext.Consumer>
{theme => (
<div style={{ background: theme.background }}>
Контент с темой
</div>
)}
</ThemeContext.Consumer>
<Mouse>
{useCallback(({ x, y }) => (
<div>{x}, {y}</div>
), [])}
</Mouse>
// Плохо (создает новую функцию при каждом рендере)
<Mouse>
{({ x, y }) => <div>{x}, {y}</div>}
</Mouse>
// Хорошо
renderCursor = ({ x, y }) => <div>{x}, {y}</div>;
<Mouse>
{this.renderCursor}
</Mouse>
Паттерн | Плюсы | Минусы |
---|---|---|
Render Props | Гибкость, прозрачность данных | Сложность вложенности |
HOC | Меньше вложенность | Сложная отладка, prop collisions |
Hooks | Простота, нет вложенности | Только для функциональных компонентов |
Render Props можно комбинировать с хуками:
function MouseTracker() {
const { x, y } = useMouse();
return <div>Позиция: {x}, {y}</div>;
}
// Или комбинированный подход
<Mouse>
{({ x, y }) => <MouseTracker x={x} y={y} />}
</Mouse>
children
как функциюПример современной альтернативы с хуками:
// Вместо
<Mouse>
{({ x, y }) => <div>{x}, {y}</div>}
</Mouse>
// Можно использовать хук
const { x, y } = useMouse();
return <div>{x}, {y}</div>;