Sobes.tech
Junior

Jak poprawnie zmieniać stan komponentów w React?

sobes.tech AI

Odpowiedź od AI

Zmiana stanu w React zachodzi za pomocą metody setState dla komponentów klasowych lub za pomocą hooka useState dla komponentów funkcyjnych.

Komponenty klasowe:

// Import React
import React, { Component } from 'react';

// Tworzymy komponent klasowy
class MyComponent extends Component {
  // Inicjujemy stan
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  // Metoda do zmiany stanu
  incrementCount = () => {
    // Używamy setState
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Licznik: {this.state.count}</p>
        <button onClick={this.incrementCount}>Zwiększ</button>
      </div>
    );
  }
}

// Eksportujemy komponent
export default MyComponent;
  • setState jest asynchroniczne.
  • setState łączy nowy stan z obecnym (shallow merge).
  • setState może przyjąć funkcję zwracającą nowy stan oparty na poprzednim:
// Metoda do zmiany stanu z użyciem funkcji
incrementCountFunction = () => {
  this.setState((prevState) => ({
    count: prevState.count + 1
  }));
};

Komponenty funkcyjne (z użyciem useState):

// Import React i useState
import React, { useState } from 'react';

// Tworzymy komponent funkcyjny
function MyFunctionComponent() {
  // Inicjujemy stan za pomocą useState
  const [count, setCount] = useState(0); // [obecny stan, funkcja do aktualizacji]

  // Funkcja do zmiany stanu
  const incrementCount = () => {
    // Używamy funkcji do aktualizacji
    setCount(count + 1);
  };

  return (
    <div>
      <p>Licznik: {count}</p>
      <button onClick={incrementCount}>Zwiększ</button>
    </div>
  );
}

// Eksportujemy komponent
export default MyFunctionComponent;
  • useState zwraca tablicę z dwoma elementami: obecnym stanem i funkcją do jego aktualizacji.
  • Funkcja do aktualizacji stanu, zwracana przez useState, zastępuje obecny stan, a nie go łączy.
  • Można przekazać funkcję do funkcji aktualizacji, jeśli nowy stan zależy od poprzedniego:
// Funkcja do zmiany stanu z użyciem funkcji
const incrementCountFunction = () => {
  setCount(prevCount => prevCount + 1);
};

Ważne punkty przy zmianie stanu:

  • Nie modyfikuj bezpośrednio stanu: Nigdy nie przypisuj nowej wartości do właściwości state bezpośrednio (np. this.state.count = 5 lub count = 5). React nie wykryje tej zmiany i komponent nie zostanie ponownie wyrenderowany.
  • Zmiana obiektów i tablic: Przy zmianie obiektów lub tablic w stanie, zawsze twórz nowe kopie. React porównuje odwołania do obiektów/tablic, i jeśli odwołanie się nie zmienia, React zakłada, że dane się nie zmieniły i nie wywołuje ponownego renderowania.
// Zmiana obiektu w komponencie klasowym
this.setState(prevState => ({
  user: {
    ...prevState.user, // Kopiujemy stare właściwości
    name: 'Nowa nazwa' // Aktualizujemy potrzebną właściwość
  }
}));

// Zmiana tablicy w komponencie funkcyjnym
setItems(prevItems => [...prevItems, 'Nowy element']); // Dodajemy nowy element
  • Asynchroniczność setState: Jeśli chcesz wykonać akcję po tym, jak stan zostanie zaktualizowany i komponent ponownie się wyrenderuje, użyj drugiego argumentu setState (funkcji zwrotnej) lub hooka useEffect w komponentach funkcyjnych.
// Callback w setState
this.setState({ count: this.state.count + 1 }, () => {
  console.log('Stan zaktualizowany!');
});
// useEffect do reagowania na zmianę stanu
useEffect(() => {
  console.log('Stan count się zmienił:', count);
}, [count]); // Zależność: hook zostanie wywołany przy zmianie count

Porównanie metod:

Cecha Komponent klasowy (setState) Komponent funkcyjny (useState)
Składnia Metoda this.setState(newState[, callback]) Hook const [state, setState] = useState(initialState)
Łączenie/Zamiana Łączy nowy stan z obecnym (shallow merge) Zastępuje obecny stan nowym
Asynchroniczność Asynchroniczne Funkcja aktualizacji jest asynchroniczna przy wywołaniu z obsługi zdarzeń, ale synchroniczna podczas fazy renderowania React
Zależność od poprzedniego stanu Przekazanie funkcji do setState: this.setState(prevState => ({...})) Przekazanie funkcji do funkcji aktualizacji: setState(prev => ({...}))