React.Component — podstawowa klasa do tworzenia komponentów z wykorzystaniem dziedziczenia w React. Przed pojawieniem się hooków w wersji 16.8 komponenty klasowe były jedynym sposobem zarządzania stanem i cyklem życia. Według danych React, 2024, komponenty klasowe są nadal wspierane, choć funkcjonalne z hookami są zalecane dla nowych projektów.
Najważniejsze
React.Component — abstrakcyjna klasa, która udostępnia wbudowane metody do pracy ze stanem, propsami i cyklem życia komponentu. Aby utworzyć komponent klasowy, należy zdefiniować klasę dziedziczącą po React.Component i zaimplementować metodę render.
React.Component pojawił się w pierwszej wersji React (2013) i pozostawał głównym sposobem tworzenia komponentów przez pięć lat. Ekosystem React budował się wokół klas: komponenty wyższego rzędu (HOC), render props, kontekst — wszystkie te wzorce zostały zaimplementowane przez składnię klasową.
Wraz z wydaniem React 16.8 w 2019 roku zespół React przedstawił hooki jako alternatywę dla klas. Hooki rozwiązywały te same zadania — stan, efekty, kontekst — ale bez dziedziczenia i skomplikowanego wiązania kontekstu. React.Component pozostaje w pełni wspierany, ale dla nowych projektów zalecane jest podejście funkcjonalne.
Minimalny komponent klasowy — klasa z jedyną metodą render, zwracającą element React. render — jedyna obowiązkowa metoda. Powinna być czystą funkcją od this.props i this.state: ten sam zestaw propsów i stanu daje ten sam wynik.
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Konstruktor jest wykonywany przed montowaniem. W nim wywoływane jest super(props) w celu przekazania propsów do klasy nadrzędnej i inicjalizowany jest this.state. Używanie konstruktora do innych celów — subskrypcji, wywołań API — nie jest zalecane: do tego służy componentDidMount.
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <p>Count: {this.state.count}</p>;
}
}
this.state — obiekt zawierający dane komponentu. Zmienianie go bezpośrednio (this.state.count = 1) jest zabronione — nie wywołuje to ponownego renderowania i łamie przewidywalność. Aktualizować stan należy przez this.setState, który tworzy nowy obiekt stanu i uruchamia ponowne renderowanie.
setState może przyjmować obiekt lub funkcję. Forma funkcyjna jest preferowana, gdy nowy stan zależy od poprzedniego: this.setState(prev => ({ count: prev.count + 1 })). React może grupować wiele setState w jeden batch w celu optymalizacji wydajności.
class Toggle extends Component {
constructor(props) {
super(props);
this.state = { isOn: false };
}
handleClick() {
this.setState(prev => ({ isOn: !prev.isOn }));
}
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
Ważna właściwość setState — jest asynchroniczny. Po wywołaniu setState stan nie aktualizuje się natychmiast. Jeśli trzeba wykonać działanie po aktualizacji, przekaż callback jako drugi argument: this.setState(newState, () => console.log(this.state)).
Komponenty klasowe mają predefiniowane metody, które React wywołuje w określonych momentach. Montowanie — constructor → render → componentDidMount. Aktualizacja — render → componentDidUpdate. Odmontowanie — componentWillUnmount.
| Metoda | Faza | Przeznaczenie |
|---|---|---|
| constructor | Montowanie | Inicjalizacja state i wiązanie metod |
| render | Za każdym razem | Zwracanie elementów React (obowiązkowe) |
| componentDidMount | Po montowaniu | Zapytania API, subskrypcje, timery |
| componentDidUpdate | Po aktualizacji | Reakcja na zmianę propsów/stanu |
| componentWillUnmount | Przed usunięciem | Czyszczenie subskrypcji, timerów, wypisywanie się z zdarzeń |
componentDidMount — główne miejsce dla efektów ubocznych po pierwszym renderowaniu. Tutaj wykonywane są żądania HTTP, nawiązywane połączenia WebSocket i uruchamiane timery. Jeśli nie wyczyścisz subskrypcji w componentWillUnmount, wystąpi wyciek pamięci.
class UserProfile extends Component {
componentDidMount() {
fetch(`/api/users/${this.props.userId}`)
.then(res => res.json())
.then(data => this.setState({ user: data }));
}
componentWillUnmount() {
// Anuluj żądanie przy odmontowaniu
}
render() {
return <div>{this.state.user?.name}</div>;
}
}
W JavaScript metody klasy domyślnie nie są związane z instancją. Jeśli przekażesz metodę jako callback — do obsługi zdarzenia, timera — this będzie undefined (w trybie strict) lub window (bez trybu strict). Bez wiązania this.setState wyrzuci błąd.
Istnieją trzy sposoby wiązania: bind w konstruktorze, funkcja strzałkowa w callbacku i class field z funkcją strzałkową. Pierwszy sposób to oficjalne zalecenie React: bind raz w konstruktorze, bez ponownego tworzenia funkcji przy każdym renderowaniu.
// Metoda 1: bind w konstruktorze (zalecane)
class MyComponent extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}
Class field — nowoczesna składnia z automatycznym wiązaniem. Funkcja strzałkowa we właściwości klasy przechwytuje this z zakresu widoczności konstruktora. Wadą jest to, że metoda jest tworzona na każdej instancji, a nie na prototypie, co zwiększa pamięć dla setek komponentów tego samego typu.
Wybór między klasą a funkcją — to nie tylko kwestia składni. Komponenty funkcjonalne z hookami rozwiązują problemy właściwe klasom: powielanie logiki w różnych metodach cyklu życia (componentDidMount + componentDidUpdate), złożoność z this i niemożność wyodrębnienia powiązanej logiki do wielokrotnego użytku.
Komponenty funkcjonalne są łatwiejsze w testowaniu — nie mają wewnętrznego stanu (który przed hookami był tylko w klasach) i nie wymagają montowania w DOM do sprawdzania callbacków. React zaleca komponenty funkcjonalne dla wszystkich nowych projektów, dokumentacja i przykłady są pisane na nich.
Komponenty klasowe pozostają najlepszym wyborem przy pracy z starszym kodem. Jeśli projekt został rozpoczęty przed 2019 rokiem, prawdopodobnie zawiera tysiące komponentów klasowych. Przepisywanie ich wszystkich na hooki w jednym sprincie jest ryzykowne. React gwarantuje wsteczną zgodność: komponenty klasowe nie zostaną usunięte.
Stopniowa migracja zaczyna się od analizy komponentu. Proste komponenty bez stanu (stateless) są tłumaczone jako pierwsze — trywialnie zastępuje się je funkcjami. Następnie — komponenty z jednym-dwoma polami stanu, gdzie useState bezpośrednio zastępuje this.state i this.setState.
Złożone komponenty z wieloma metodami cyklu życia są tłumaczone przez useEffect. Logika z componentDidMount + componentDidUpdate jest dzielona na osobne useEffect z różnymi zależnościami. componentWillUnmount jest zastępowany funkcją zwracaną wewnątrz useEffect. Do złożonej logiki stanu używaj useReducer.
Narzędzia automatycznej migracji — @phenomnomnominal/ts-react-class-to-hook lub skrypty codemod — mogą automatycznie konwertować proste klasy. W skomplikowanych przypadkach migracja pozostaje ręczną pracą, wymagającą zrozumienia logiki oryginalnego komponentu.
Często zadawane pytania
Tak. super(props) przekazuje propsy do nadrzędnego React.Component. Bez tego wywołania this.props będzie undefined wewnątrz konstruktora. W render i metodach cyklu życia propsy są dostępne nawet bez super, ale to efekt uboczny implementacji.
React grupuje wiele wywołań setState w jeden batch w celu zmniejszenia liczby niepotrzebnych ponownych renderowań. Gdyby setState był synchroniczny, każde wywołanie powodowałoby natychmiastowe renderowanie, obniżając wydajność przy masowych aktualizacjach.
Nie. Hooki działają tylko w komponentach funkcjonalnych. Dla projektów z komponentami klasowymi dostępne są wszystkie stare wzorce: render props, HOC i Consumer dla kontekstu. Migracja na hooki wymaga przekształcenia klasy w funkcję.
React.PureComponent implementuje shouldComponentUpdate z płytkim (shallow) porównaniem propsów i stanu. W przeciwieństwie do Component, który zawsze przerenderowuje przy setState, PureComponent pomija przerenderowanie, jeśli dane się nie zmieniły. Jest to optymalizacja dla komponentów bez złożonego zagnieżdżenia.
Użyj componentDidCatch i getDerivedStateFromError. componentDidCatch(error, info) loguje błąd. getDerivedStateFromError aktualizuje state do wyświetlenia fallback-UI. Te metody działają tylko w komponentach klasowych — funkcje potrzebują opakowującego komponentu ErrorBoundary.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również