Skip to main content
Практика завдань

Шаблон render props у React

Що таке патерн Render Props?

Render props — це патерн, при якому компонент отримує функцію як пропс, яка повертає елементи React. Це дозволяє компоненту ділитися своєю внутрішньою логікою/станом, дозволяючи споживачу контролювати рендеринг.


Основний приклад

tsx
// Компонент з render prop — ділиться позицією миші function MouseTracker({ render }: { render: (position: { x: number; y: number }) => React.ReactNode; }) { const [position, setPosition] = useState({ x: 0, y: 0 }); const handleMouseMove = (e: React.MouseEvent) => { setPosition({ x: e.clientX, y: e.clientY }); }; return ( <div onMouseMove={handleMouseMove} style={{ height: "100vh" }}> {render(position)} </div> ); } // Споживач контролює UI function App() { return ( <MouseTracker render={({ x, y }) => ( <p>Миша знаходиться на ({x}, {y})</p> )} /> ); }

Використання дітей як Render Prop

tsx
function MouseTracker({ children }: { children: (position: { x: number; y: number }) => React.ReactNode; }) { const [position, setPosition] = useState({ x: 0, y: 0 }); return ( <div onMouseMove={e => setPosition({ x: e.clientX, y: e.clientY })}> {children(position)} </div> ); } // Використання — чистіший синтаксис <MouseTracker> {({ x, y }) => <span>({x}, {y})</span>} </MouseTracker>

Практичні приклади

Компонент Toggle

tsx
function Toggle({ children }: { children: (props: { isOn: boolean; toggle: () => void }) => React.ReactNode; }) { const [isOn, setIsOn] = useState(false); const toggle = () => setIsOn(prev => !prev); return <>{children({ isOn, toggle })}</>; } // Повторно використовувана логіка перемикання, різні UI <Toggle> {({ isOn, toggle }) => ( <button onClick={toggle}> {isOn ? "УВІМКНУТО" : "ВИМКНУТО"} </button> )} </Toggle> <Toggle> {({ isOn, toggle }) => ( <div className={`switch ${isOn ? "active" : ""}`} onClick={toggle} /> )} </Toggle>

Завантажувач даних

tsx
function DataFetcher<T>({ url, children }: { url: string; children: (props: { data: T | null; loading: boolean; error: string | null }) => React.ReactNode; }) { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<string | null>(null); useEffect(() => { fetch(url) .then(res => res.json()) .then(setData) .catch(e => setError(e.message)) .finally(() => setLoading(false)); }, [url]); return <>{children({ data, loading, error })}</>; } // Використання <DataFetcher<User[]> url="/api/users"> {({ data, loading, error }) => { if (loading) return <Spinner />; if (error) return <Error message={error} />; return <UserList users={data!} />; }} </DataFetcher>

Render Props vs Кастомні Хуки

ОсобливістьRender PropsКастомні Хуки
Повторне використання логіки
Без обгорткового компонента❌ (додає обгортку)
Працює в класових компонентах
Може контролювати рендеринг
ЧитабельністьМоже стати вкладенимЧистіше
tsx
// Така ж логіка як Кастомний Хук (сучасний підхід) function useMousePosition() { const [position, setPosition] = useState({ x: 0, y: 0 }); useEffect(() => { const handler = (e: MouseEvent) => setPosition({ x: e.clientX, y: e.clientY }); window.addEventListener("mousemove", handler); return () => window.removeEventListener("mousemove", handler); }, []); return position; } // Використання — чистіше, без обгортки function App() { const { x, y } = useMousePosition(); return <p>({x}, {y})</p>; }

Важливо:

Render props — це потужний патерн для ділення станом логіки між компонентами. Хоча кастомні хуки в основному замінили render props у сучасному React, цей патерн все ще цінний у бібліотеках (наприклад, React Router, Formik, Downshift) і коли вам потрібні компоненти, які працюють як з класовими, так і з функціональними компонентами.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань