Чем отличается функциональный компонент от классового?

Функциональный компонент и классовый компонент в React — это два способа создания компонентов, которые выполняют одну и ту же задачу: описывают, как должен выглядеть и вести себя пользовательский интерфейс. Однако они различаются синтаксисом, подходом к управлению состоянием и жизненным циклом, а также исторически имели разное место в экосистеме React.

1. Синтаксис

Функциональные компоненты — это обычные JavaScript-функции, которые принимают props как аргумент и возвращают JSX.

function Welcome(props) {
return <h1>Привет, {props.name}</h1>;
}

или с использованием стрелочной функции:

const Welcome = ({ name }) => <h1>Привет, {name}</h1>;

Классовые компоненты — это ES6-классы, которые наследуются от React.Component. Они обязательно должны реализовать метод render, который возвращает JSX.

class Welcome extends React.Component {
render() {
return <h1>Привет, {this.props.name}</h1>;
}
}

2. Управление состоянием (state)

Функциональные компоненты (до 2019) не могли иметь своё состояние. Всё состояние приходилось поднимать вверх и передавать через props. Однако с появлением React Hooks (начиная с версии 16.8), функциональные компоненты получили возможность использовать состояние и другие функции жизненного цикла через хуки.

import { useState } from 'react';
function Counter() {
const \[count, setCount\] = useState(0);
return (
<>
&lt;p&gt;Счёт: {count}&lt;/p&gt;
&lt;button onClick={() =&gt; setCount(count + 1)}>+1&lt;/button&gt;
&lt;/&gt;
);
}

Классовые компоненты изначально имели встроенное состояние через this.state и метод this.setState() для его изменения.

class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<>
&lt;p&gt;Счёт: {this.state.count}&lt;/p&gt;
&lt;button onClick={this.increment}&gt;+1&lt;/button&gt;
&lt;/&gt;
);
}
}

3. Методы жизненного цикла (Lifecycle Methods)

Классовые компоненты используют специальные методы жизненного цикла, такие как:

  • componentDidMount

  • componentDidUpdate

  • componentWillUnmount

  • shouldComponentUpdate

  • getDerivedStateFromProps

  • и другие

class Timer extends React.Component {
componentDidMount() {
this.timer = setInterval(() => {
console.log('Тик');
}, 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return &lt;p&gt;Таймер запущен&lt;/p&gt;;
}
}

Функциональные компоненты реализуют жизненный цикл через хуки, такие как useEffect, который объединяет поведение componentDidMount, componentDidUpdate и componentWillUnmount.

import { useEffect } from 'react';
function Timer() {
useEffect(() => {
const timer = setInterval(() => {
console.log('Тик');
}, 1000);
return () => clearInterval(timer); // аналог componentWillUnmount
}, \[\]); // пустой массив  аналог componentDidMount
return &lt;p&gt;Таймер запущен&lt;/p&gt;;
}

4. Чтение и обновление props

В функциональных компонентах props передаются как аргумент функции:

function Greeting(props) {
return &lt;h1&gt;{props.message}&lt;/h1&gt;;
}

или с деструктуризацией:

const Greeting = ({ message }) => &lt;h1&gt;{message}&lt;/h1&gt;;

В классовых компонентах props доступны через this.props:

class Greeting extends React.Component {
render() {
return &lt;h1&gt;{this.props.message}&lt;/h1&gt;;
}
}

5. Контекст (Context API)

Обе модели могут использовать Context, но в функциональных компонентах можно применять хук useContext:

const value = useContext(MyContext);

В классовом компоненте:

class MyComponent extends React.Component {
static contextType = MyContext;
render() {
return &lt;p&gt;Значение: {this.context}&lt;/p&gt;;
}
}

6. Читабельность и компактность

Функциональные компоненты:

  • Проще по синтаксису

  • Легче читаются

  • Меньше шаблонного кода

  • Лучше подходят для декларативного программирования

Классовые компоненты:

  • Более громоздкие

  • Требуют this, bind, конструкторов и методов жизненного цикла

  • Код может быть менее читаемым при усложнении логики

7. Поддержка хуков

Хуки (useState, useEffect, useMemo, useCallback, useReducer, и т.д.) можно использовать только в функциональных компонентах.

В классовых компонентах хуки недоступны. Логика должна реализовываться через методы жизненного цикла и классовое состояние.

8. Переиспользование логики

В функциональных компонентах повторно использовать логику можно с помощью пользовательских хуков:

function useCounter() {
const \[count, setCount\] = useState(0);
const increment = () => setCount(c => c + 1);
return { count, increment };
}
function Counter() {
const { count, increment } = useCounter();
return (
<>
&lt;p&gt;{count}&lt;/p&gt;
&lt;button onClick={increment}&gt;+1&lt;/button&gt;
&lt;/&gt;
);
}

В классовых компонентах переиспользование логики чаще достигается через HOC (компоненты высшего порядка) или render props, что сложнее в реализации и понимании.

9. Обработка событий

В функциональных компонентах обработчики событий не требуют bind:

&lt;button onClick={() =&gt; alert('Нажато')}>Нажми&lt;/button&gt;

В классовом компоненте:

class MyButton extends React.Component {
handleClick = () => alert('Нажато');
render() {
return &lt;button onClick={this.handleClick}&gt;Нажми&lt;/button&gt;;
}
}

Раньше нужно было использовать this.handleClick.bind(this) или объявлять обработчики через стрелочные функции в теле класса.

10. Поддержка и развитие

React-команда официально рекомендует использовать функциональные компоненты с хуками. Большинство новых библиотек, примеров и официальная документация ориентированы именно на этот подход.

Классовые компоненты продолжают поддерживаться, но не развиваются и не получают новых возможностей (например, новые хуки не могут быть использованы в классах).