Quest: Częsty błąd z useState

Licznik z błędem

Przeanalizuj poniższy przykład, a następnie go uruchom. Czy działa zgodnie z oczekiwaniem?

import React, { useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  const handleIncrement = () => {
    // Błąd: oba wywołania używają starej wartości count
    setCount(count + 1);
    setCount(count + 1);
  };

  return (
    <div style={{ padding: "20px" }}>
      <h1>Błędne zwiększanie licznika</h1>
      <p>Licznik: {count}</p>
      <button onClick={handleIncrement}>Zwiększ dwa razy</button>
    </div>
  );
}

export default App;

React grupuje wiele zmian stanu lub propsów w jednym renderze, zamiast renderować komponent osobno po każdej zmianie. Jeśli w jednej funkcji wywołasz setState kilka razy, React nie wykona tyle renderów, ile wywołań tylko zrobi tylko jeden render na koniec.
Poprawna wersja:

const handleIncrement = () => {
    // Poprawnie: każda aktualizacja korzysta z aktualnej wartości
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
  };

Przykład z tablicą

import React, { useState } from "react";

function App() {
  const [items, setItems] = useState([]);

  const addItems = () => {
    // Błąd: oba wywołania używają starej wartości items
    setItems([...items, "A"]);
    setItems([...items, "B"]);
  };

  return (
    <div style={{ padding: "20px" }}>
      <h1>Błędne dodawanie elementów</h1>
      <button onClick={addItems}>Dodaj A i B</button>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Napisz poprawną wersję addItems wykorzystującą prev

Zasada: Używaj setState(prev => …) gdy:

  • nowa wartość zależy od poprzedniej
  • aktualizujesz licznik
  • aktualizujesz tablicę
  • aktualizujesz obiekt

Twój komentarz

Zapisz moje dane, adres e-mail i witrynę w przeglądarce aby wypełnić dane podczas pisania kolejnych komentarzy.