Render Props — это паттерн проектирования компонентов, позволяющий разделять логику и визуальное представление. Основная идея заключается в передаче функции через пропсы, которая возвращает JSX, управляя тем, как компонент отображается.
В Preact компонент с Render Props принимает функцию в качестве пропса
(обычно с именем render или аналогичным) и вызывает её
внутри своего рендера, передавая необходимое состояние или методы:
import { h, Component } from 'preact';
class MouseTracker extends Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({ x: event.clientX, y: event.clientY });
};
render() {
return (
<div style={{ height: '100vh' }} onMouseM ove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
export default function App() {
return (
<MouseTracker render={({ x, y }) => (
<p>Координаты мыши: {x}, {y}</p>
)} />
);
}
Ключевой момент: MouseTracker не определяет, как именно
будут отображены координаты мыши. Он только предоставляет данные через
функцию-проп.
Повторное использование логики Один и тот же компонент может использоваться с разным визуальным представлением, сохраняя общий функционал.
Изоляция состояния Состояние компонента управляется внутри него, а не в родителе, что упрощает поддержку и тестирование.
Гибкость отображения Можно передавать любые функции для рендера, включая сложные JSX-структуры, условия и анимации.
В Preact, начиная с версии X, можно комбинировать Render Props с хуками для управления состоянием без классов:
import { h } from 'preact';
import { useState } from 'preact/hooks';
function Toggle({ render }) {
const [on, setOn] = useState(false);
const toggle = () => setOn(prev => !prev);
return render({ on, toggle });
}
export default function App() {
return (
<Toggle render={({ on, toggle }) => (
<button onCl ick={toggle}>
{on ? 'Включено' : 'Выключено'}
</button>
)} />
);
}
Паттерн сохраняет преимущества классовых компонентов, но уменьшает количество кода и упрощает синтаксис.
Render Props позволяет передавать не только состояние, но и методы для его изменения. Это особенно полезно для создания комплексных компонентов с взаимодействием между различными частями:
function Form({ render }) {
const [value, setValue] = useState('');
const handleChange = (e) => setValue(e.target.value);
const reset = () => setValue('');
return render({ value, handleChange, reset });
}
export default function App() {
return (
<Form render={({ value, handleChange, reset }) => (
<div>
<input value={value} onIn put={handleChange} />
<button onCl ick={reset}>Сбросить</button>
</div>
)} />
);
}
Такой подход минимизирует дублирование кода и обеспечивает явное управление состоянием.
Render Props хорошо типизируются, что позволяет строго определять передаваемые данные:
interface MouseProps {
x: number;
y: number;
}
interface MouseTrackerProps {
render: (props: MouseProps) => JSX.Element;
}
const MouseTracker: preact.FunctionComponent<MouseTrackerProps> = ({ render }) => {
const [coords, setCoords] = useState({ x: 0, y: 0 });
const handleMouseMove = (event: MouseEvent) => {
setCoords({ x: event.clientX, y: event.clientY });
};
return <div onMouseM ove={handleMouseMove}>{render(coords)}</div>;
};
Типизация повышает надёжность и удобство использования компонентов с Render Props в больших приложениях.
Render Props отлично сочетается с Preact Context для передачи состояния глубоко вложенным компонентам без проброса через все уровни:
import { createContext } from 'preact';
import { useContext } from 'preact/hooks';
const ThemeContext = createContext('light');
function Themed({ render }) {
const theme = useContext(ThemeContext);
return render(theme);
}
export default function App() {
return (
<ThemeContext.Provider value="dark">
<Themed render={(theme) => <p>Текущая тема: {theme}</p>} />
</ThemeContext.Provider>
);
}
Это сочетание позволяет создавать мощные, гибкие и легко поддерживаемые компоненты.
Render Props остаётся актуальным инструментом проектирования компонентов в Preact, особенно в случаях, когда необходима высокая гибкость и повторное использование логики без жёсткой привязки к визуальной реализации.