Functional Component — це спосіб створення компонентів React за допомогою звичайних JavaScript-функцій, який став стандартом після виходу React 16.8 і появи хуків. Функціональні компоненти приймають props і повертають React-елементи, не вимагаючи наслідування від React.Component. За даними React, 2024, 97% нових компонентів в екосистемі React пишуться як функції.
Головне
Functional Component (функціональний компонент) — це React-компонент, визначений як функція, що приймає об'єкт props і повертає React-елемент. До React 16.8 такі компоненти називалися stateless (без стану), тому що вони не могли керувати внутрішнім станом.
З появою хуків у React 16.8 (лютий 2019) функціональні компоненти отримали доступ до стану (useState), побічних ефектів (useEffect), контексту (useContext) та рефів (useRef). Термін «stateless» застарів — сучасні функціональні компоненти повноцінно керують станом.
React офіційно рекомендує функціональні компоненти як основний спосіб створення компонентів. Вся документація на react.dev, приклади, туторіали та нові API (Server Components, Actions) побудовані на функціональному підході. Класові компоненти не видалені, але нові можливості React доступні лише через хуки.
Найпростіший функціональний компонент — функція, що повертає JSX. Він приймає props як аргумент, не вимагає конструктора, виклику super або прив'язки this. Props доступні безпосередньо через аргумент функції — жодного this.props.
// Functional component without state
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Arrow function (common variant)
const Greeting = ({ name }) => (
<h1>Hello, {name}!</h1>
);
Для додавання стану використовуйте useState. Хук повертає кортеж із двох значень: поточний стан і функція-сетер. На відміну від класового this.setState, useState замінює значення цілком, а не зливає з попереднім.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Хуки — основа сучасного React. Кожен хук вирішує конкретне завдання: useState — стан, useEffect — побічні ефекти, useContext — доступ до контексту, useRef — посилання на DOM-елементи, useCallback та useMemo — мемоізація.
useEffect замінює componentDidMount, componentDidUpdate та componentWillUnmount одночасно. Перший аргумент — callback з ефектом, другий — масив залежностей. Якщо масив порожній, ефект виконується один раз після монтування. Якщо залежності вказані — при кожній зміні будь-якої з них.
import React, { useState, useEffect } from 'react';
function UserData({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
if (!cancelled) setUser(data);
});
// Cleanup - analog of componentWillUnmount
return () => { cancelled = true; };
}, [userId]); // Dependency
return <div>{user?.name}</div>;
}
Головна перевага функціональних компонентів — повторне використання логіки через кастомні хуки. Якщо в класовому компоненті логіка дублювалася між componentDidMount та componentDidUpdate, у функціональному вона виноситься в окрему функцію з префіксом use. Кастомні хуки — основна альтернатива HOC та render props.
React рекомендує композицію, а не наслідування для повторного використання коду між компонентами. Функціональні компоненти ідеально підходять для композиції: один компонент може містити кілька інших, передаючи їм props та children.
Паттерн children — коли компонент приймає дочірні елементи через проп children — реалізується природно: function Layout({ children }). Аналог slots із Vue реалізується через іменовані пропси-компоненти: function Page({ header, sidebar, content }).
Наслідування в React практично не використовується. Навіть класові компоненти, які технічно підтримують extends, рідко утворюють ієрархії глибше одного рівня. Функціональні компоненти з композицією повністю покривають потреби у повторному використанні коду без наслідування.
Функціональні компоненти отримують вбудовані механізми оптимізації. React.memo — аналог PureComponent для функцій: запобігає ререндеру, якщо props не змінилися (поверхневе порівняння). useMemo кешує результат обчислень між рендерами.
import React, { useMemo } from 'react';
// React.memo - memoize component
const ExpensiveList = React.memo(({ items }) => {
return <ul>
{items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>;
});
// useMemo - caching result
function Dashboard({ transactions }) {
const summary = useMemo(() => {
return transactions.reduce((acc, t) => acc + t.amount, 0);
}, [transactions]);
return <p>Total: {summary}</p>;
}
useCallback мемоізує функції-колбеки, щоб вони не створювалися заново при кожному рендері. Це критично при передачі функцій у дочірні компоненти, обгорнуті в React.memo: без useCallback дочірній компонент буде ререндеритися щоразу, тому що посилання на функцію змінюється.
Різниця між підходами виходить за рамки синтаксису. Функціональні компоненти — це замикання: стан та ефекти прив'язані до конкретного рендеру. Класові компоненти — це this: стан завжди береться з this.state, який може бути застарілим на момент виконання асинхронного колбека.
| Аспект | Функціональний | Класовий |
|---|---|---|
| Стан | useState (ізольований) | this.state + this.setState |
| Ефекти | useEffect з залежностями | componentDidMount + componentDidUpdate |
| Контекст | useContext | Context.Consumer або static contextType |
| Оптимізація | React.memo + useMemo | PureComponent + shouldComponentUpdate |
| Логіка повторно | Кастомні хуки | HOC / Render props |
| this | Немає | bind у конструкторі |
Функціональні компоненти дають лінійний потік виконання. У класовому компоненті пов'язана логіка часто розмазана по кількох lifecycle-методах. Наприклад, підписка на WebSocket встановлюється в componentDidMount і видаляється в componentWillUnmount. У функціональному компоненті обидві операції — в одному useEffect з return-функцією очищення.
TypeScript з функціональними компонентами працює природніше, ніж з класами. Типізація пропсів — інтерфейс для аргументу функції. Тип значення, що повертається — JSX.Element або ReactNode. useState автоматично виводить тип із початкового значення.
import React, { useState } from 'react';
interface ButtonProps {
label: string;
variant?: 'primary' | 'secondary';
onClick: () => void;
}
const Button: React.FC<ButtonProps> =
({ label, variant = 'primary', onClick }) => (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{label}
</button>
);
Сучасний TypeScript дозволяє типізувати useReducer з дискримінованими union-типами, Generics у кастомних хуках і строгу перевірку children через React.PropsWithChildren. Функціональні компоненти з TypeScript дають повну безпеку типів без додаткових абстракцій.
Часті запитання
Функціональні компоненти простіші: немає конструктора, bind, this та розрізнених lifecycle-методів. Хуки дозволяють групувати пов'язану логіку. React вкладає ресурси в розвиток хуків, а не класів. Server Components та нові фічі доступні лише у функціях.
Так, через useEffect з таймером всередині та cleanup-функцією для clearInterval. Зверніть увагу на замикання: якщо тікати лічильник, використовуйте функціональну форму setState: setCount(c => c + 1), щоб не залежати від старого значення в замиканні.
Використовуйте useRef для зберігання попереднього значення. Оновлюйте ref у useEffect після кожного рендеру. Кастомний хук usePrevious допомагає для чистого порівняння: const prev = usePrevious(value);
React.memo — HOC для мемоізації цілого компонента: запобігає ререндеру, якщо props не змінилися. useMemo — хук для мемоізації конкретного значення всередині компонента: кешує результат функції між рендерами за масивом залежностей.
Найпростіший спосіб — useState з ініціалізацією від props + useEffect із залежністю від props для синхронізації. Для рідкісних випадків React рекомендує використовувати ключ (key) для примусового перестворення компонента при зміні вхідних даних.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.