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 для функций: предотвращает ререндер, если пропсы не изменились (поверхностное сравнение). 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 для мемоизации целого компонента: предотвращает ререндер, если пропсы не изменились. useMemo — хук для мемоизации конкретного значения внутри компонента: кеширует результат функции между рендерами по массиву зависимостей.
Самый простой способ — useState с инициализацией от props + useEffect с зависимостью от props для синхронизации. Для редких случаев React recommends: используйте ключ (key) для принудительного пересоздания компонента при изменении входных данных.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также