Дізнайтеся, як React Concurrent Mode революціонізує оптимізацію батареї завдяки енергоефективному рендерингу, покращуючи досвід користувача та сприяючи сталому вебу. Розглянемо ключові примітиви та стратегії.
Оптимізація батареї в React Concurrent Mode: енергоефективний рендеринг для сталого вебу
У нашому дедалі більш взаємопов'язаному світі, де мільярди користувачів щодня отримують доступ до веб-додатків на безлічі пристроїв, ефективність нашого програмного забезпечення ніколи не була такою важливою. Окрім швидкості, зростає усвідомлення екологічного та особистого впливу нашого цифрового сліду – зокрема, споживання енергії веб-додатками. Хоча ми часто надаємо пріоритет відгукливості та візуальному багатству, тихе виснаження батарей пристроїв та ширші екологічні витрати неефективного рендерингу є проблемами, які вимагають нашої уваги. Саме тут React Concurrent Mode постає як трансформаційна сила, що дозволяє розробникам створювати не лише швидші, але й більш енергоефективні та сталі веб-досвіди за допомогою того, що ми називаємо "енергоефективним рендерингом".
Цей вичерпний посібник розглядає, як React Concurrent Mode, представлений у React 18, фундаментально переосмислює наш підхід до рендерингу, пропонуючи потужні примітиви для оптимізації роботи батареї та покращення досвіду користувачів у всьому світі. Ми розглянемо традиційні виклики, основні концепції Concurrent Mode, практичні стратегії та ширші наслідки для більш енергосвідомого вебу.
Традиційна модель React: вузьке місце продуктивності та пожирач енергії
До появи React Concurrent Mode модель рендерингу React була переважно синхронною. Коли відбувалося оновлення стану, React перемальовував усе дерево компонентів (або його частини) у блокуючий спосіб. Це означало, що після початку рендерингу його не можна було перервати. Якщо оновлення було обчислювально інтенсивним або зачіпало велику кількість компонентів, воно могло блокувати головний потік браузера на значний час, що призводило до кількох небажаних наслідків:
- Невідгукливий UI: Користувачі стикалися з "завислим" інтерфейсом, не маючи змоги взаємодіяти з кнопками, прокручувати чи вводити текст, що призводило до розчарування та відчуття повільності.
- Ривки та заїкання (Jank and Stutter): Анімації та переходи виглядали уривчастими, оскільки головний потік був занадто зайнятий, щоб встигати рендерити кадри з частотою 60 кадрів на секунду (fps).
- Високе завантаження CPU: Постійні та часто непотрібні перемальовування, особливо під час швидких змін стану (наприклад, введення тексту в поле пошуку), тримали CPU активним, споживаючи значну кількість енергії.
- Збільшене навантаження на GPU: Інтенсивні маніпуляції з DOM та часті перемальовування також можуть навантажувати GPU, що ще більше сприяє розрядженню батареї, особливо на мобільних пристроях.
Розглянемо додаток для електронної комерції зі складним фільтром товарів. Коли користувач вводить пошуковий запит, синхронна модель рендерингу може запускати повне перемальовування списку товарів з кожним натисканням клавіші. Це не тільки робить поле введення повільним, але й витрачає дорогоцінні цикли CPU на перемальовування елементів, які ще не є критичними, поки користувач ще друкує. Цей сукупний ефект у мільярдах веб-сесій щодня перетворюється на значний глобальний енергетичний слід.
Знайомство з React Concurrent Mode: зміна парадигми для ефективних UI
React Concurrent Mode, наріжний камінь React 18, є фундаментальною зміною у способі обробки оновлень у React. Замість попереднього синхронного підходу "все або нічого", Concurrent Mode робить рендеринг переривчастим. Він вводить систему пріоритетів та планувальник, який може призупиняти, відновлювати або навіть скасовувати роботу з рендерингу залежно від терміновості оновлення. Основна обіцянка — підтримувати відгукливість UI, навіть під час важких обчислювальних завдань або мережевих запитів, надаючи пріоритет взаємодіям, що бачить користувач.
Ця зміна парадигми стала можливою завдяки кільком базовим механізмам:
- Fibers: Внутрішній алгоритм узгодження React використовує дерево Fiber, яке є зв'язаним списком робочих одиниць. Це дозволяє React розбивати роботу з рендерингу на менші, керовані частини.
- Планувальник (Scheduler): Планувальник вирішує, яка робота має вищий пріоритет. Введення користувача (наприклад, клік або набір тексту) вважається високопріоритетним, тоді як фонове завантаження даних або некритичні оновлення UI мають нижчий пріоритет.
- Розподіл часу (Time Slicing): React може "нарізати" роботу з рендерингу на невеликі частини та періодично повертати контроль браузеру. Це дозволяє браузеру обробляти високопріоритетні події (наприклад, введення користувача) перед тим, як відновити низькопріоритетну роботу з рендерингу.
Роблячи рендеринг неблокуючим та переривчастим, Concurrent Mode не просто покращує сприйману продуктивність; він за своєю суттю закладає основу для енергоефективного рендерингу. Виконуючи менше непотрібної роботи або відкладаючи її на періоди простою, пристрої споживають менше енергії.
Ключові примітиви для енергоефективного рендерингу
Concurrent Mode розкриває свою потужність через кілька хуків та компонентів, які розробники можуть використовувати для керування планувальником React:
useTransition та startTransition: позначення нетермінових оновлень
Хук useTransition та його імперативний аналог, startTransition, дозволяють позначати певні оновлення стану як "переходи" (transitions). Переходи — це нетермінові оновлення, які можуть бути перервані більш критичними, терміновими оновленнями (наприклад, введенням користувача). Це неймовірно потужно для підтримки відгукливості.
Як це допомагає енергоефективному рендерингу:
- Відкладення роботи: Замість негайного перемальовування складної частини UI, перехід відкладає роботу, дозволяючи терміновим оновленням (наприклад, оновленню поля введення) завершитися першими. Це зменшує час, протягом якого CPU безперервно активний на низькопріоритетних завданнях.
- Зменшення циклів CPU: Надаючи пріоритет та потенційно скасовуючи застарілу роботу з рендерингу (якщо надходить нове, більш термінове оновлення), React уникає марнування циклів CPU на рендери, які незабаром стануть неактуальними.
Практичний приклад: фільтрація списку товарів
import React, { useState, useTransition } from 'react';
function ProductSearch() {
const [query, setQuery] = useState('');
const [displayQuery, setDisplayQuery] = useState('');
const [isPending, startTransition] = useTransition();
const products = Array.from({ length: 10000 }, (_, i) => `Product ${i}`);
const filteredProducts = products.filter(product =>
product.toLowerCase().includes(displayQuery.toLowerCase())
);
const handleChange = (e) => {
setQuery(e.target.value);
// Mark this state update as a transition
startTransition(() => {
setDisplayQuery(e.target.value);
});
};
return (
<div>
<input
type="text"
value={query}
onChange={handleChange}
placeholder="Search products..."
/>
{isPending && <p>Loading...</p>}
<ul>
{filteredProducts.map(product => (
<li key={product}>{product}</li>
))}
</ul>
</div>
);
}
У цьому прикладі введення в поле вводу негайно оновлює query (термінове оновлення), зберігаючи відгукливість поля. Дорога операція фільтрації (оновлення displayQuery) обгорнута в startTransition, що робить її переривчастою. Якщо користувач введе ще один символ до завершення фільтрації, React відмовиться від попередньої роботи з фільтрації та почне заново, заощаджуючи заряд батареї, не завершуючи рендери, які більше не потрібні.
useDeferredValue: відкладення оновлень дорогих значень
Хук useDeferredValue дозволяє відкласти оновлення значення. Концептуально це схоже на debouncing або throttling, але інтегровано безпосередньо в планувальник React. Ви передаєте йому значення, і він повертає "відкладену" версію цього значення, яка може відставати від оригіналу. React спочатку надасть пріоритет терміновим оновленням, а потім, врешті-решт, оновить відкладене значення.
Як це допомагає енергоефективному рендерингу:
- Зменшення непотрібних перемальовувань: Відкладаючи значення, що використовується в дорогій частині UI, ви запобігаєте перемальовуванню цієї частини при кожній зміні вихідного значення. React чекає на паузу в терміновій активності перед оновленням відкладеного значення.
- Використання часу простою: Це дозволяє React виконувати відкладену роботу під час періодів простою, значно зменшуючи пікове навантаження на CPU та розподіляючи обчислення, що є більш енергоефективним.
Практичний приклад: оновлення діаграми в реальному часі
import React, { useState, useDeferredValue } from 'react';
function ExpensiveChart({ data }) {
// Simulate an expensive chart rendering
console.log('Rendering ExpensiveChart with data:', data);
// A real chart component would process 'data' and draw SVG/Canvas
return <div style={{ border: '1px solid black', padding: '10px' }}>Chart for: {data.join(', ')}</div>;
}
function DataGenerator() {
const [input, setInput] = useState('');
const deferredInput = useDeferredValue(input);
const data = deferredInput.split('').map(char => char.charCodeAt(0));
const handleChange = (e) => {
setInput(e.target.value);
};
return (
<div>
<input
type="text"
value={input}
onChange={handleChange}
placeholder="Type something..."
/>
<p>Immediate Input: {input}</p>
<p>Deferred Input: {deferredInput}</p>
<ExpensiveChart data={data} />
</div>
);
}
Тут стан input оновлюється негайно, зберігаючи відгукливість текстового поля. Однак ExpensiveChart перемальовується лише тоді, коли оновлюється deferredInput, що відбувається після невеликої затримки або коли система простоює. Це запобігає перемальовуванню діаграми з кожним натисканням клавіші, заощаджуючи значну обчислювальну потужність.
Suspense: організація асинхронних операцій
Suspense дозволяє компонентам "чекати" на щось перед рендерингом – наприклад, на завантаження коду (через React.lazy) або отримання даних. Коли компонент "призупиняється" (suspends), React може показати резервний UI (наприклад, спінер завантаження), поки асинхронна операція завершується, не блокуючи головний потік.
Як це допомагає енергоефективному рендерингу:
- Ліниве завантаження (Lazy Loading): Завантажуючи код компонента лише тоді, коли він потрібен (наприклад, коли користувач переходить на певний маршрут), ви зменшуєте початковий розмір бандла та час парсингу. Менше завантажених ресурсів на початку означає меншу мережеву активність та менше обробки CPU, що заощаджує заряд батареї.
- Отримання даних: У поєднанні з бібліотеками для отримання даних, що підтримують Suspense, Suspense може організувати, коли і як дані отримуються та рендеряться. Це запобігає ефекту "водоспаду" та дозволяє React пріоритезувати рендеринг того, що вже доступно, відкладаючи менш критичні дані.
- Зменшене початкове завантаження: Менше початкове завантаження безпосередньо призводить до нижчого споживання енергії на критичному етапі запуску програми.
Практичний приклад: ліниве завантаження важкого компонента
import React, { Suspense, useState } from 'react';
const HeavyAnalyticsDashboard = React.lazy(() => import('./HeavyAnalyticsDashboard'));
function App() {
const [showDashboard, setShowDashboard] = useState(false);
return (
<div>
<h1>Main Application</h1>
<button onClick={() => setShowDashboard(true)}>
Load Analytics Dashboard
</button>
{showDashboard && (
<Suspense fallback={<div>Loading Analytics...</div>}>
<HeavyAnalyticsDashboard />
</Suspense>
)}
</div>
);
}
Компонент HeavyAnalyticsDashboard, який потенційно містить складні діаграми та візуалізації даних, завантажується та рендериться лише тоді, коли користувач явно натискає кнопку. До цього моменту його код не впливає на розмір бандла або час початкового парсингу, роблячи основний додаток легшим та більш енергоефективним при запуску.
Стратегії оптимізації батареї з Concurrent Mode
Хоча Concurrent Mode надає основу, ефективне його використання для оптимізації батареї вимагає стратегічного підходу. Ось ключові стратегії:
Пріоритезація взаємодії з користувачем та відгукливості
Основна філософія Concurrent Mode — підтримувати відгукливість UI. Визначаючи та обгортаючи некритичні оновлення за допомогою startTransition або відкладаючи значення за допомогою useDeferredValue, ви гарантуєте, що введення користувача (набір тексту, кліки, прокрутка) завжди отримує негайну увагу. Це не тільки покращує досвід користувача, але й призводить до економії енергії:
- Коли UI здається швидким, користувачі рідше швидко клікають або повторно вводять дані, зменшуючи зайві обчислення.
- Відкладаючи важкі обчислення, CPU може частіше переходити в стани з низьким енергоспоживанням між взаємодіями з користувачем.
Розумне отримання та кешування даних
Мережева активність є значним споживачем енергії, особливо на мобільних пристроях. Concurrent Mode, особливо в поєднанні з Suspense для отримання даних, дозволяє більш розумно керувати цим процесом:
- Отримання даних з підтримкою Suspense: Бібліотеки, такі як Relay або SWR (з експериментальною підтримкою Suspense), дозволяють компонентам декларувати свої потреби в даних, а React організовує їх отримання. Це може запобігти надмірному завантаженню та усунути "водоспад" запитів даних, коли один запит має завершитися до початку наступного.
- Кешування на стороні клієнта: Агресивне кешування даних на стороні клієнта (наприклад, за допомогою `localStorage`, `IndexedDB` або бібліотек, як-от React Query/SWR) зменшує потребу в повторних мережевих запитах. Менше радіоциклів означає менше споживання батареї.
- Попереднє завантаження та попереднє отримання (з розумом): Хоча попереднє завантаження ресурсів може покращити сприйману швидкість, це потрібно робити обережно. Попередньо завантажуйте лише ті ресурси, які з високою ймовірністю знадобляться найближчим часом, і розглядайте можливість використання підказок браузера, таких як
<link rel="preload">або<link rel="prefetch">, переконуючись, що вони не використовуються надмірно і не блокують критичний рендеринг.
Оптимізація перемальовувань компонентів та обчислень
Навіть з Concurrent Mode, мінімізація непотрібних обчислень та перемальовувань залишається важливою. Concurrent Mode допомагає, ефективно *плануючи* рендери, але все ж краще уникати рендерів, коли це можливо.
- Мемоізація: Використовуйте
React.memoдля чистих функціональних компонентів,useMemoдля дорогих обчислень таuseCallbackдля стабілізації посилань на функції, що передаються дочірнім компонентам. Ці техніки запобігають перемальовуванню, коли пропси або залежності не змінилися, зменшуючи роботу, яку потрібно планувати Concurrent Mode. - Виявлення "Render Thrashing": Використовуйте профайлер React DevTools для виявлення компонентів, які перемальовуються надмірно. Оптимізуйте їхнє керування станом або передачу пропсів, щоб зменшити непотрібні оновлення.
- Перенесення важких обчислень у Web Workers: Для CPU-інтенсивних завдань (наприклад, обробка зображень, складні алгоритми, великі трансформації даних) перенесіть їх з головного потоку у Web Workers. Це звільняє головний потік для оновлень UI, дозволяючи Concurrent Mode підтримувати відгукливість та уникати високого використання CPU в головному потоці, який зазвичай є найбільш енергоємним.
Ефективне керування ресурсами
Ресурси, такі як зображення, шрифти та відео, часто є найбільшим внеском у вагу сторінки і можуть значно впливати на час роботи батареї через витрати на передачу по мережі та рендеринг.
- Оптимізація зображень:
- Сучасні формати: Використовуйте формати зображень нового покоління, такі як WebP або AVIF, які пропонують краще стиснення без помітної втрати якості, зменшуючи розміри файлів та передачу по мережі.
- Адаптивні зображення: Надавайте зображення різних розмірів залежно від пристрою та області перегляду користувача (
<img srcset>,<picture>). Це дозволяє уникнути завантаження непотрібно великих зображень на менших екранах. - Ліниве завантаження: Використовуйте атрибут
loading="lazy"на тегах<img>або JavaScript Intersection Observers для завантаження зображень лише тоді, коли вони потрапляють в область перегляду. Це значно зменшує початковий час завантаження та мережеву активність.
- Стратегії завантаження шрифтів: Оптимізуйте завантаження кастомних шрифтів, щоб запобігти блокуванню рендерингу. Використовуйте
font-display: swapабоoptional, щоб текст був видимим швидко, і розгляньте можливість самостійного хостингу шрифтів, щоб зменшити залежність від сторонніх серверів. - Оптимізація відео та медіа: Стискайте відео, використовуйте відповідні формати (наприклад, MP4 для широкої сумісності, WebM для кращого стиснення) та ліниво завантажуйте відеоелементи. Уникайте автовідтворення відео, якщо це не є абсолютно необхідним.
Анімація та візуальні ефекти
Плавні анімації є вирішальними для хорошого досвіду користувача, але погано оптимізовані анімації можуть бути серйозним споживачем енергії.
- Надавайте перевагу CSS-анімаціям: Завжди, коли це можливо, використовуйте CSS-анімації та переходи (наприклад, для властивостей
transformтаopacity). Вони часто апаратно прискорені та керуються композиторним потоком браузера, що зменшує навантаження на головний потік та CPU. requestAnimationFrameдля JS-анімацій: Для більш складних анімацій, керованих JavaScript, використовуйтеrequestAnimationFrame. Це гарантує, що анімації синхронізовані з циклом перемальовування браузера, запобігаючи непотрібним рендерам та ривкам, і дозволяючи Concurrent Mode ефективно планувати іншу роботу.- Мінімізуйте "Layout Thrashing": Уникайте примусового перерахунку макета або стилю браузером кілька разів в межах одного кадру. Групуйте читання та запис DOM, щоб запобігти вузьким місцям у продуктивності та зменшити споживання енергії.
Вимірювання та моніторинг споживання енергії
Пряме вимірювання споживання енергії веб-додатком у браузері є складним завданням, оскільки браузери не надають детальних API для енергії. Однак ми можемо використовувати проксі-метрики та усталені інструменти для висновків про енергоефективність:
- Використання CPU: Високе та тривале використання CPU є сильним індикатором високого споживання енергії. Моніторте використання CPU в інструментах розробника браузера (наприклад, Task Manager у Chrome, вкладка Performance).
- Мережева активність: Надмірні або неефективні мережеві запити споживають значну кількість енергії. Аналізуйте мережеві "водоспади" в DevTools, щоб знайти можливості для скорочення або оптимізації.
- Частота перемальовувань: Часті або великі перемальовування можуть вказувати на непотрібну роботу з рендерингу. Вкладка "Rendering" у DevTools може підсвічувати області перемальовування.
- Інструменти розробника браузера:
- Вкладка Performance у Chrome DevTools: Надає детальну хронологію активності головного потоку, рендерингу, виконання скриптів та малювання. Шукайте тривалі завдання, сплески CPU та надмірні періоди простою (де Concurrent Mode може проявити себе).
- Lighthouse: Автоматизований інструмент, який аудитує веб-сторінки на предмет продуктивності, доступності, SEO та найкращих практик. Його оцінки продуктивності корелюють з енергоефективністю, оскільки швидші та легші сторінки зазвичай споживають менше енергії.
- Web Vitals: Метрики, такі як Largest Contentful Paint (LCP), First Input Delay (FID) та Cumulative Layout Shift (CLS), є чудовими індикаторами досвіду користувача і часто корелюють з базовою енергоефективністю. Додаток з хорошими показниками Web Vitals зазвичай виконує менше непотрібної роботи.
- Моніторинг реальних користувачів (RUM): Інтегруйте рішення RUM для збору даних про продуктивність від реальних користувачів у польових умовах. Це надає важливі відомості про те, як ваш додаток працює на різноманітних пристроях та в різних мережевих умовах по всьому світу, допомагаючи вам виявити реальні сценарії, що виснажують енергію.
Ключовим є встановлення базових показників, проведення цілеспрямованих оптимізацій з використанням Concurrent Mode, а потім повторне вимірювання для підтвердження покращень.
Глобальний вплив та стала веб-розробка
Прагнення до енергоефективного рендерингу з React Concurrent Mode стосується не лише індивідуального досвіду користувача; воно має глибокі глобальні наслідки:
- Екологічні переваги: Сукупний ефект мільярдів веб-сесій, оптимізованих для енергоефективності, може призвести до значного скорочення глобального споживання енергії дата-центрами та кінцевими пристроями користувачів. Це безпосередньо сприяє пом'якшенню наслідків зміни клімату та просуванню більш сталої цифрової екосистеми.
- Економічні переваги: Для користувачів у регіонах з дорогими тарифними планами на дані менша кількість мережевих запитів означає менше споживання мобільних даних, що робить веб-додатки більш доступними та дешевими. Для бізнесу покращена продуктивність призводить до кращого утримання користувачів, вищих показників конверсії та зниження витрат на інфраструктуру (оскільки для обробки повільних клієнтів потрібно менше серверних ресурсів).
- Доступність та рівність: Продовження часу роботи батареї пристрою є вирішальним фактором для користувачів у всьому світі, особливо в районах з обмеженим доступом до надійної інфраструктури для зарядки. Енергоефективний веб гарантує, що більше людей зможуть довше отримувати доступ до інформації та послуг, долаючи цифрові розриви.
- Довговічність пристроїв: Зменшуючи навантаження на апаратне забезпечення пристрою (CPU, GPU, батарея), енергоефективний рендеринг може сприяти подовженню терміну служби пристроїв, зменшуючи кількість електронних відходів та просуваючи принципи циркулярної економіки.
Прийняття принципів енергоефективного рендерингу, посилених React Concurrent Mode, наближає нас до справді "зеленого" та справедливого вебу, доступного та корисного для всіх і всюди.
Виклики та міркування
Хоча Concurrent Mode пропонує величезні переваги, його впровадження не позбавлене певних міркувань:
- Крива навчання: Розробникам потрібно зрозуміти нові ментальні моделі для оновлень стану, зокрема, коли і як ефективно використовувати
startTransitionтаuseDeferredValue. - Переведення існуючих додатків: Міграція великого, усталеного додатку React для повного використання Concurrent Mode вимагає ретельного планування та поетапного впровадження, оскільки це стосується фундаментальної поведінки рендерингу.
- Налагодження конкурентних проблем: Налагодження асинхронного та переривчастого рендерингу іноді може бути складнішим, ніж синхронного. React DevTools пропонують хорошу підтримку, але розуміння потоку є ключовим.
- Підтримка та сумісність браузерів: Хоча сам Concurrent Mode є частиною React, базові можливості браузера (наприклад, пріоритети планувальника) можуть впливати на його ефективність. Важливо стежити за розвитком браузерів.
Практичні кроки для розробників
Щоб розпочати свій шлях до енергоефективного рендерингу з React Concurrent Mode, розгляньте ці практичні кроки:
- Оновіться до React 18: Це основний крок. Переконайтеся, що ваш проєкт використовує React 18 або новішу версію для доступу до функцій Concurrent Mode.
- Визначте некритичні оновлення: Проведіть аудит вашого додатку на наявність місць, де введення користувача викликає дорогі, нетермінові оновлення (наприклад, пошукові фільтри, складні валідації форм, оновлення дашбордів). Це головні кандидати для
startTransition. - Використовуйте
startTransitionтаuseDeferredValue: Почніть з рефакторингу невеликих, ізольованих компонентів для використання цих хуків. Спостерігайте за різницею у відгукливості та сприйманій продуктивності. - Інтегруйте
Suspenseдля коду та даних: ВикористовуйтеReact.lazyдля розділення коду, щоб зменшити початковий розмір бандла. Досліджуйте рішення для отримання даних з підтримкою Suspense для більш ефективного завантаження даних. - Регулярно профілюйте та вимірюйте: Зробіть профілювання продуктивності рутинною частиною вашого процесу розробки. Використовуйте інструменти розробника браузера та Lighthouse для постійного моніторингу та виявлення вузьких місць.
- Навчайте свою команду: Створюйте культуру усвідомлення продуктивності та енергоефективності у вашій команді розробників. Діліться знаннями та найкращими практиками використання Concurrent Mode.
Майбутнє енергоефективного рендерингу в React
React Concurrent Mode — це не статична функція; це філософія, що розвивається. Команда React продовжує вдосконалювати планувальник та впроваджувати нові можливості, які ще більше посилять енергоефективний рендеринг. Оскільки браузери також еволюціонують, надаючи більш складні API для планування та функції енергозбереження, React, ймовірно, буде інтегруватися з ними, щоб запропонувати ще глибші оптимізації.
Ширша спільнота веб-розробників все більше визнає важливість сталих веб-практик. Підхід React з Concurrent Mode є значним кроком до того, щоб дозволити розробникам створювати додатки, які є не тільки продуктивними та приємними для користувачів, але й поважають час роботи батареї їхніх пристроїв та ресурси планети.
На завершення, React Concurrent Mode надає потужні інструменти для створення веб-додатків, які за своєю суттю є більш енергоефективними та відгукливими. Розуміючи та стратегічно застосовуючи його примітиви, такі як useTransition, useDeferredValue та Suspense, розробники можуть створювати досвіди, які радують користувачів своєю плавністю, одночасно сприяючи більш сталому та доступному глобальному вебу. Шлях до енергоефективного рендерингу є безперервним, але з React Concurrent Mode у нас є чіткий і потужний шлях уперед.