Чего нет в функциональных компонентах что было в классовых
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Функциональные 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 - это лучший выбор.