Functional Component — начин за създаване на React компоненти с помощта на обикновени JavaScript функции, който стана стандарт след пускането на React 16.8 и появата на hooks. Функционалните компоненти приемат props и връщат React елементи, без да изискват наследяване от React.Component. Според данни на React, 2024, 97% от новите компоненти в екосистемата на React се пишат като функции.
Основните
Functional Component (функционален компонент) — React компонент, дефиниран като функция, която приема обект props и връща React елемент. Преди React 16.8 такива компоненти се наричаха stateless (без състояние), защото не можеха да управляват вътрешно състояние.
С появата на hooks в React 16.8 (февруари 2019) функционалните компоненти получиха достъп до състояние (useState), странични ефекти (useEffect), контекст (useContext) и референции (useRef). Терминът „stateless" е остарял — модерните функционални компоненти напълно управляват състоянието.
React официално препоръчва функционалните компоненти като основен начин за създаване на компоненти. Цялата документация на react.dev, примерите, уроците и новите API (Server Components, Actions) са изградени върху функционалния подход. Класовите компоненти не са премахнати, но новите възможности на React са достъпни само чрез hooks.
Най-простият функционален компонент — функция, връщаща 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. Hook-ът връща кортеж от две стойности: текущо състояние и функция-setter. За разлика от класовия 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>
);
}
Hooks са основата на модерния React. Всеки hook решава конкретна задача: 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>;
}
Основното предимство на функционалните компоненти — повторно използване на логика чрез персонализирани hooks. Ако в класовия компонент логиката се дублираше между componentDidMount и componentDidUpdate, във функционалния тя се извлича в отделна функция с префикс use. Персонализираните hooks са основната алтернатива на HOC и render props.
React препоръчва композиция, а не наследяване за повторно използване на код между компоненти. Функционалните компоненти са идеални за композиция: един компонент може да съдържа няколко други, предавайки им props и children.
Моделът children — когато компонент приема наследници чрез prop children — се имплементира естествено: function Layout({ children }). Аналогът на slots от Vue се имплементира чрез именувани props-компоненти: 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 мемоизира callback функции, за да не се създават наново при всяко рендериране. Това е критично при предаване на функции на наследници, обвити в React.memo: без useCallback, наследникът ще се рендерира всеки път, защото референцията към функцията се променя.
Разликата между подходите надхвърля синтаксиса. Функционалните компоненти — са затваряне: състоянието и ефектите са обвързани с конкретно рендериране. Класовите компоненти — са this: състоянието винаги се взема от this.state, който може да е остарял в момента на изпълнение на асинхронен callback.
| Аспект | Функционален | Класов |
|---|---|---|
| Състояние | useState (изолирано) | this.state + this.setState |
| Ефекти | useEffect със зависимости | componentDidMount + componentDidUpdate |
| Контекст | useContext | Context.Consumer или static contextType |
| Оптимизация | React.memo + useMemo | PureComponent + shouldComponentUpdate |
| Повторно използване на логика | Персонализирани hooks | HOC / Render props |
| this | Няма | bind в конструктора |
Функционалните компоненти осигуряват линеен поток на изпълнение. В класовия компонент свързаната логика често е разпръсната в няколко метода на жизнения цикъл. Например абонаментът за WebSocket се настройва в componentDidMount и се премахва в componentWillUnmount. Във функционалния компонент и двете операции — в един useEffect с функция за почистване.
TypeScript с функционални компоненти работи по-естествено, отколкото с класове. Типизиране на props — интерфейс за аргумента на функцията. Типът на връщаната стойност — 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 в персонализирани hooks и строга проверка на children чрез React.PropsWithChildren. Функционалните компоненти с TypeScript дават пълна типова безопасност без допълнителни абстракции.
Често задавани въпроси
Функционалните компоненти са по-прости: няма конструктор, bind, this и разпръснати методи на жизнения цикъл. Hooks позволяват групиране на свързана логика. React инвестира ресурси в развитието на hooks, а не на класове. Server Components и новите функции са достъпни само във функции.
Да, чрез useEffect с таймер вътре и функция за почистване за clearInterval. Обърнете внимание на затварянето: ако тиктакате брояч, използвайте функционалната форма на setState: setCount(c => c + 1), за да не зависите от старата стойност в затварянето.
Използвайте useRef за съхранение на предишната стойност. Актуализирайте ref в useEffect след всяко рендериране. За визуално сравнение помага персонализираният hook usePrevious: const prev = usePrevious(value);
React.memo — HOC за мемоизация на цял компонент: предотвратява повторно рендериране, ако props не са се променили. useMemo — hook за мемоизация на конкретна стойност вътре в компонента: кешира резултата на функцията между рендериранията въз основа на масив от зависимости.
Най-простият начин — useState с инициализация от props + useEffect със зависимост от props за синхронизиране. За редки случаи React препоръчва: използвайте ключ (key) за принудително пресъздаване на компонента при промяна на входните данни.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също