Specyfikacja ES2023 wprowadza teraz cztery metody tablic — toSorted, toReversed, toSpliced oraz with — które zwracają nowe tablice zamiast mutować oryginalną. W React oraz innych bibliotekach UI opartych na niezmiennych (immutable) stanach, pomocniki te pozwalają programistom zastąpić sztuczki z operatorem spread, które od dawna były źródłem błędów i powtarzalnego kodu (boilerplate).

Dlaczego ta zmiana jest ważna

React decyduje o tym, czy ponownie wyrenderować komponent, porównując referencję poprzedniego stanu z nową. Jeśli referencja pozostaje bez zmian, React zakłada, że nic się nie zmieniło. Klasyczna metoda Array.prototype.sort sortuje tablicę w miejscu i zwraca tę samą referencję, więc wywołanie typu setTasks(prev => prev.sort(fn)) sprawia, że React nie zauważa aktualizacji. Interfejs użytkownika pozostaje z nieaktualnymi danymi — jest to błąd, który bardzo często pojawia się w rzeczywistych projektach.

Programiści obchodzili ten problem, najpierw klonując tablicę — zazwyczaj za pomocą operatora spread — tak aby krok sortowania generował nową referencję:

setTasks(prev => [...prev].sort((a, b) => b.priority - a.priority));

Ten wzorzec działa, ale wprowadza niepotrzebny szum w kodzie i łatwo o nim zapomnieć. Nowe metody ES2023 oferują bezpośredni i czytelny sposób na utworzenie nowej tablicy przy zachowaniu oryginalnej nienaruszonej.

Cztery metody nie zmieniające stanu (non-mutating)

  • toSorted(compareFn?) – zachowuje się jak sort, ale zwraca posortowaną kopię. Brak zmian w tablicy źródłowej.
  • toReversed() – zastępuje reverse. Zwraca odwróconą kopię, pozostawiając oryginalną kolejność nienaruszoną.
  • toSpliced(start, deleteCount, ...items) – odzwierciedla splice bez efektów ubocznych. Zwrócona tablica uwzględnia wstawienie lub usunięcie, a źródło pozostaje bez zmian.
  • with(index, value) – podmienia element na pozycji index na value i zwraca nową tablicę. Zastępuje powszechny wzorzec użycia map lub operatora spread do podmiany elementu.

Wszystkie cztery metody są częścią standardu ECMAScript i są dostępne w aktualnych wersjach głównych przeglądarek oraz w Node.js 20.

Jak wygląda teraz kod

Sortowanie listy

// Before
setTasks(prev => [...prev].sort((a, b) => b.priority - a.priority));

// After
setTasks(prev => prev.toSorted((a, b) => b.priority - a.priority));

Aktualizacja pojedynczego elementu

// Before
setItems(prev =>
  prev.map((item, i) => (i === idx ? newItem : item))
);

// After
setItems(prev => prev.with(idx, newItem));

Odwracanie tablicy

setLogs(prev => prev.toReversed());

Usuwanie elementu

setTags(prev => prev.toSpliced(removeIdx, 1));

Nowa składnia eliminuje potrzebę stosowania dodatkowych operatorów spread lub pętli mapujących, dzięki czemu aktualizacje stanu są łatwiejsze do odczytania i mniej podatne na błędy.

Kto zyskuje, a kto może się wahać

Programiści korzystający z React, Vue, Redux, Zustand lub jakiegokolwiek frameworka oczekującego niezmiennych struktur danych, zyskują jaśniejszy model mentalny: wywołujesz metodę, otrzymujesz nową tablicę i przekazujesz ją do funkcji ustawiającej (setter). Redukcja boilerplate'u może również skrócić cykle renderowania o kilka milisekund, ponieważ silnik unika tworzenia pośredniej kopii przed sortowaniem.

Zespoły obsługujące starsze przeglądarki mogą potrzebować polyfillów. Metody te nie występują w starszych wersjach Safari czy Internet Explorera, więc build produkcyjny celujący w te platformy musi zawierać rozwiązanie zastępcze (fallback). Dodaje to niewielki koszt w postaci rozmiaru paczki (bundle size), ale zysk w czytelności jest zazwyczaj tego wart.

Autorzy bibliotek mogą potrzebować aktualizacji definicji typów (np. TypeScript), aby udostępnić nowe sygnatury. Dopóki te definicje nie trafią do oficjalnych pakietów @types, programiści mogą napotykać tymczasowe błędy typów.

Na co warto zwrócić uwagę

  • Metryki adopcji – narzędzia takie jak ESLint mogą wkrótce dodać reguły flagujące mutowalne wywołania tablic w setterach stanu, zachęcając programistów do korzystania z nowych metod.
  • Badania wydajności – wczesne benchmarki sugerują, że natywne metody nie zmieniające stanu są szybsze niż klonowanie operatorem spread, a następnie operacja mutująca, ale rzeczywiste dane potwierdzą ten wpływ.
  • Dalsze propozycje – komitet ECMAScript kontynuuje badanie API domyślnie niezmiennych (immutable-by-default); śledzenie nadchodzących etapów może ujawnić więcej pomocników pasujących do tego samego wzorca.

Podsumowanie

Najnowsza specyfikacja ECMAScript daje programistom UI wbudowany, zwięzły sposób na zachowanie niezmienności stanu bez akrobatyki z operatorem spread, która powodowała niezliczone błędy. Podmieniając sort, reverse, splice oraz podmiany oparte na indeksie na toSorted, toReversed, toSpliced i with, pozwalasz mechanizmowi wykrywania zmian w React działać zgodnie z przeznaczeniem i sprawiasz, że Twój kod jest łatwiejszy do odczytania. Jeśli Twoje docelowe przeglądarki obsługują nowe metody — lub jesteś gotów użyć polyfilli — nadszedł czas, aby wycofać stare wzorce i pozwolić językowi wykonać najcięższą pracę.