← Назад к вопросам

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

2.0 Middle🔥 181 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Функциональные vs Классовые компоненты: что потеряли

Отличный вопрос о переходе с классовых компонентов на функциональные. Хотя React 16.8 (hooks) уравнял функциональные компоненты с классовыми в возможностях, есть некоторые различия в подходе.

Что буквально нет в функциональных компонентах

1. Метод getSnapshotBeforeUpdate

Этот редкий метод жизненного цикла НЕ имеет эквивалента в hooks:

class MyComponent extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.list.length < this.props.list.length) {
      return this.listRef.scrollHeight - this.listRef.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      this.listRef.scrollTop = this.listRef.scrollHeight - snapshot;
    }
  }
}

Функциональный компонент - нет встроенной поддержки, нужно использовать useLayoutEffect.

2. componentDidCatch и ErrorBoundary

Error Boundaries - это компоненты класса для перехвата ошибок в потомках. Функциональных аналогов нет:

class ErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    console.log('Поймали ошибку:', error);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Что-то сломалось</h1>;
    }
    return this.props.children;
  }
}

Функциональный компонент НЕ может быть ErrorBoundary.

3. setState callback

В классовых компонентах setState может принимать callback:

this.setState({ count: 1 }, () => {
  console.log('DOM обновлен');
});

В функциональных нужно использовать useEffect как workaround.

Что было в классовых, но по-другому в функциональных

1. Инициализация state

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
}

function Counter(props) {
  const [state, setState] = useState(() => {
    return { count: 0 };
  });
}

2. shouldComponentUpdate

class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return nextProps.id !== this.props.id;
  }
}

const MyComponent = React.memo((props) => <div>{props.id}</div>);

3. Управление контекстом

class MyComponent extends React.Component {
  componentDidMount() {
    this.context.subscribe();
  }
}
MyComponent.contextType = MyContext;

function MyComponent() {
  const context = useContext(MyContext);
  useEffect(() => {
    context.subscribe();
  }, [context]);
}

Чем функциональные компоненты ЛУЧШЕ

Да, что-то потеряли, но много получили:

const useWindowSize = () => {
  const [size, setSize] = useState({ width: 0, height: 0 });
  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  return size;
};

Преимущества:

  • Переиспользование логики через custom hooks
  • Проще читать и понимать
  • Меньше boilerplate
  • Лучше работает с TypeScript
  • Лучше для tree-shaking и оптимизаций

Практический пример - замена getSnapshotBeforeUpdate

function ChatWindow(props) {
  const listRef = useRef(null);
  const prevScrollHeightRef = useRef(0);

  useLayoutEffect(() => {
    prevScrollHeightRef.current = listRef.current.scrollHeight - listRef.current.scrollTop;
  });

  useLayoutEffect(() => {
    if (prevScrollHeightRef.current !== null) {
      listRef.current.scrollTop = listRef.current.scrollHeight - prevScrollHeightRef.current;
    }
  });

  return <div ref={listRef}>{props.messages}</div>;
}

Вывод

Функциональные компоненты - это будущее React. Потеря нескольких методов жизненного цикла компенсируется большей простотой, лучшей переиспользуемостью через hooks и лучшей поддержкой TypeScript. В 99% случаев функциональные компоненты с hooks - это лучший выбор.