Вступ
У React використання дизайнерських патернів може призвести до більш масштабованих, підтримуваних та ефективних застосунків. Ця стаття досліджує деякі основні патерни проектування в React, такі як патерн контейнерних і презентаційних компонентів, патерн вищого порядку (Higher-Order Component, HOC), патерн Render Props та патерн кастомних хуків. Кожен патерн буде проілюстровано за допомогою сучасних хуків React.
1. Патерн контейнерних та презентаційних компонентів
Концепція: Цей патерн розділяє компоненти на дві категорії: контейнерні компоненти (розумні компоненти), які обробляють стан та логіку, та презентаційні компоненти (тупі компоненти), які відповідають за відображення інтерфейсу.
Переваги:
- Розподіл відповідальності: Зберігає бізнес-логіку окремо від рендерингу UI.
- Повторне використання: Презентаційні компоненти можна використовувати в різних частинах застосунку.
Реалізація:
Контейнерний компонент:
// TodoContainer.js
import React, { useState, useEffect } from 'react';
import TodoList from './TodoList';
const TodoContainer = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
fetch('/api/todos')
.then(response => response.json())
.then(data => setTodos(data));
}, []);
return ;
};
export default TodoContainer;
Презентаційний компонент:
// TodoList.js
import React from 'react';
const TodoList = ({ todos }) => (
{todos.map(todo => (
{todo.text}
))}
);
export default TodoList;
2. Патерн вищого порядку (Higher-Order Component, HOC)
Концепція: Компонент вищого порядку (HOC) — це функція, яка приймає компонент і повертає новий компонент з додатковими пропсами або поведінкою.
Переваги:
- Повторне використання коду: Інкапсулює загальну поведінку, яку можна використовувати в кількох компонентах.
- Розширення: Дозволяє розширювати компоненти додатковою функціональністю.
Реалізація:
// withLogging.js
import React, { useEffect } from 'react';
const withLogging = WrappedComponent => {
return props => {
useEffect(() => {
console.log('Component mounted');
}, []);
return ;
};
};
export default withLogging;
// MyComponent.js
import React from 'react';
import withLogging from './withLogging';
const MyComponent = () =>
Hello, World!
;
export default withLogging(MyComponent);
3. Патерн Render Props
Концепція: Цей патерн передбачає використання пропсу, який є функцією, для спільного використання коду між компонентами.
Переваги:
- Гнучкість: Забезпечує спосіб передачі динамічної поведінки компонентам.
- Повторне використання коду: Сприяє повторному використанню коду, передаючи функції як пропси.
Реалізація:
// MouseTracker.js
import React, { useState } from 'react';
const MouseTracker = ({ render }) => {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = event => {
setPosition({
x: event.clientX,
y: event.clientY
});
};
return (
{render(position)}
);
};
export default MouseTracker;
// App.js
import React from 'react';
import MouseTracker from './MouseTracker';
const App = () => (
(
The mouse position is ({x}, {y})
)} />
);
export default App;
## Патерн кастомних хуків
**Концепція**: Кастомні хуки дозволяють інкапсулювати логіку та управління станом у повторно використовувані функції.

**Переваги**:
- **Повторне використання коду**: Витягує і повторно використовує логіку в різних компонентах.
- **Спрощення**: Спрощує логіку компонентів, переміщуючи складну логіку в хуки.
**Реалізація**:
// useFetchData.js
import { useState, useEffect } from 'react';
const useFetchData = url => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => setData(data));
}, [url]);
return data;
};
export default useFetchData;
```
// DataDisplay.js
import React from 'react';
import useFetchData from './useFetchData';
const DataDisplay = ({ url }) => {
const data = useFetchData(url);
return data ?
{JSON.stringify(data, null, 2)}
:
Loading...
;
};
export default DataDisplay;
5. Патерн комбінованих компонентів
Концепція: Патерн комбінованих компонентів дозволяє комбінувати компоненти разом, щоб сформувати єдину цілісну одиницю, де кожен компонент вносить свій вклад у досягнення більшої мети.
Переваги:
- Інкапсуляція: Компоненти працюють разом безшовно, при цьому кожен з них зберігає свою відповідальність.
- Гнучкість: Користувачі можуть налаштовувати поведінку і вигляд комбінованого компонента через його частини.
Реалізація:
// Toggle.js
import React, { useState } from 'react';
const Toggle = ({ children }) => {
const [on, setOn] = useState(false);
const toggle = () => {
setOn(!on);
};
const getChildProps = () => {
return {
on,
toggle,
};
};
return <>{React.Children.map(children, child => React.cloneElement(child, getChildProps()))};
};
export default Toggle;
// ToggleButton.js
import React from 'react';
const ToggleButton = ({ on, toggle }) => (
{on ? 'Turn Off' : 'Turn On'}
);
export default ToggleButton;
// ToggleMessage.js
import React from 'react';
const ToggleMessage = ({ on }) => (
{on ? 'The button is ON' : 'The button is OFF'}
);
export default ToggleMessage;
// App.js
import React from 'react';
import Toggle from './Toggle';
import ToggleButton from './ToggleButton';
import ToggleMessage from './ToggleMessage';
const App = () => (
);
export default App;
- Компонент Toggle: Керує станом (
on
абоoff
) та надає функціюtoggle
своїм дітям через патерн комбінованих компонентів. - Компонент ToggleButton: Отримує стан
on
і функціюtoggle
як пропси для обробки подій кліку та відображення відповідного тексту. - Компонент ToggleMessage: Отримує стан
on
для відображення повідомлення в залежності від поточного стану.
Цей патерн дозволяє компонентам ToggleButton
і ToggleMessage
працювати разом безшовно під керівництвом компонента Toggle
, демонструючи інкапсуляцію і гнучкість патерну комбінованих компонентів.
Висновок
Розуміння та впровадження патернів проектування в React з хуками може значно підвищити масштабованість, підтримуваність і ефективність ваших застосунків. Використовуючи патерни, такі як контейнерні та презентаційні компоненти, компоненти вищого порядку (Higher-Order Components, HOC), Render Props, комбіновані компоненти та кастомні хуки, ви можете створювати модульний і повторно використовуваний код, який відповідає кращим практикам. Експериментуйте з цими патернами, щоб побачити, як вони можуть покращити ваші React проекти.
Перекладено з: ✈️ Design Patterns in React (2025) 📈