Специфікація ES2023 тепер містить чотири методи масивів — toSorted, toReversed, toSpliced та with, — які повертають нові масиви замість мутації оригіналу. У React та інших UI-бібліотеках, що покладаються на незмінний (immutable) стан, ці помічники дозволяють розробникам замінити трюки зі spread-оператором, які довгий час були джерелом багів та шаблонного коду.

Чому це важливо

React вирішує, чи потрібно перерендерити компонент, порівнюючи посилання на попередній стан із новим. Якщо посилання не змінилося, React вважає, що нічого не змінилося. Класичний метод Array.prototype.sort сортує масив на місці (in place) і повертає те саме посилання, тому такий виклик, як setTasks(prev => prev.sort(fn)), залишає React «сліпим» до оновлення. Інтерфейс залишається заблокованим на застарілих даних — це баг, який занадто часто трапляється в реальних проєктах.

Розробники обходили цю проблему, спочатку клонуючи масив — зазвичай за допомогою spread-оператора, — щоб крок сортування створював нове посилання:

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

Цей патерн працює, але він створює зайвий шум і про нього легко забути. Нові методи ES2023 пропонують прямий і зрозумілий спосіб створення нового масиву, залишаючи оригінал недоторканим.

Чотири методи без мутації

  • toSorted(compareFn?) — працює як sort, але повертає відсорковану копію. Оригінальний масив не змінюється.
  • toReversed() — замінює reverse. Він повертає реверсну копію, зберігаючи оригінальний порядок недоторканим.
  • toSpliced(start, deleteCount, ...items) — дублює функціонал splice без побічних ефектів. Повернений масив відображає вставлення або видалення, а вихідний масив залишається незмінним.
  • with(index, value) — замінює елемент за індексом index на value і повертає новий масив. Він замінює поширений патерн використання map або заміни елемента через spread-оператор.

Всі чотири методи є частиною стандарту ECMAScript і доступні в сучасних версіях основних браузерів та Node.js 20.

Як тепер виглядає код

Сортування списку

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

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

Оновлення одного елемента

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

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

Реверс масиву

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

Видалення елемента

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

Новий синтаксис усуває потребу в додаткових spread-операторах або циклах mapping, роблячи оновлення стану легшими для читання та менш схильними до помилок.

Кому це вигідно і хто може вагатися

Розробники, які використовують React, Vue, Redux, Zustand або будь-який фреймворк, що очікує незмінні структури даних, отримують чіткішу ментальну модель: викликаєте метод, отримуєте новий масив, передаєте його в сеттер. Скорочення шаблонного коду також може зекономити кілька мілісекунд у циклах рендерингу, оскільки рушій уникає створення проміжної копії перед сортуванням.

Команди з підтримкою застарілих браузерів можуть потребувати використання поліфілів. Ці методи відсутні в старих версіях Safari або Internet Explorer, тому production-білд, що орієнтований на ці платформи, повинен містити fallback. Це додає невелику вагу бандлу, але перевага в читабельності зазвичай того варта.

Автори бібліотек можуть знадобитися оновити визначення типів (наприклад, TypeScript), щоб відкрити нові сигнатури. Доки ці визначення не з'являться в офіційних пакетах @types, розробники можуть стикатися з тимчасовими помилками типізації.

На що звернути увагу далі

  • Метрики впровадження — інструменти на кшталт ESLint незабаром можуть додати правила, які позначатимуть виклики мутабельних методів масиву в сеттерах стану, підштовхуючи розробників до використання нових методів.
  • Дослідження продуктивності — перші бенчмарки свідчать, що нативні немутабельні методи працюють швидше, ніж клонування через spread-оператор з наступною мутабельною операцією, але реальні дані підтвердять цей вплив.
  • Подальші пропозиції — комітет ECMAScript продовжує досліджувати API, які є незмінними за замовчуванням; стеження за наступними етапами може виявити більше помічників, що відповідають тому самому патерну.

Підсумок

Остання специфікація ECMAScript надає UI-розробникам вбудований лаконічний спосіб підтримувати незмінність стану без «акробатики» зі spread-оператором, яка спричиняла незліченну кількість багів. Замінюючи sort, reverse, splice та заміну за індексом на toSorted, toReversed, toSpliced та with, ви дозволяєте механізму відстеження змін React працювати так, як задумано, і робите свій код легшим для читання. Якщо ваші цільові браузери підтримують нові методи — або ви готові використовувати поліфіли — настав час відмовитися від старих патернів і дозволити мові виконувати важку роботу.