Skip to main content

Що робить «state normalization»?

Що таке нормалізація стану

State normalization - це спосіб зберігати дані у стані в «плоскій», структурованій формі, щоб:

  • уникнути дублювання даних,
  • спростити оновлення,
  • зменшити кількість ререндерів,
  • і зробити дані передбачуваними та легко кешованими.

Приклад без нормалізації (погано)

javascript
const state = { posts: [ { id: 1, title: "React guide", author: { id: 10, name: "Tim" } }, { id: 2, title: "Redux patterns", author: { id: 10, name: "Tim" } // the author is duplicated } ] };

Тут об'єкт автора дублюється в кожному пості. Якщо автор змінить ім'я, потрібно пройтися по всіх постах і оновити копію. Крім того, кожна зміна в posts спричиняє масові ререндери.


Приклад із нормалізацією

javascript
const state = { posts: [1, 2], // just IDs users: { // dictionary of entities by ID 10: { id: 10, name: "Tim" } }, entities: { posts: { 1: { id: 1, title: "React guide", authorId: 10 }, 2: { id: 2, title: "Redux patterns", authorId: 10 } } } };

Тепер:

  • Автор зберігається в одному місці (users[10]);
  • Пости посилаються на автора через authorId;
  • При зміні автора не потрібно оновлювати всі пости.

Чому це важливо для продуктивності React

  1. Менше ререндерів
  • Під час оновлення сутності React може перемалювати лише ті компоненти, які залежать від конкретного ID.
  • Немає «ланцюгової» реакції через вкладені об'єкти.
  1. Легко порівнювати дані (shallow compare)
  • Об'єкти й масиви менш вкладені -> === і React.memo працюють ефективніше.
  1. Спрощуються оновлення
  • Зміна конкретного елемента - просто оновлення state.entities.posts[id].
  • Не потрібно перебирати весь масив.
  1. Оптимізується кеш і селектори
  • Мемоізовані селектори (наприклад, у Redux Toolkit з createSelector) працюють швидше і стабільніше.

Аналогія

Уяви, що твій state - це база даних у мініатюрі. Нормалізація перетворює його на таблиці зі зв'язками (1:1, 1:n), замість вкладених об'єктів (як «JSON у JSON»).


У React / Redux це особливо корисно

У Redux Toolkit і RTK Query це рекомендована практика. Офіційна бібліотека normalizr навіть автоматизує перетворення:

javascript
import { normalize, schema } from 'normalizr'; const user = new schema.Entity('users'); const post = new schema.Entity('posts', { author: user }); const normalizedData = normalize(originalData, [post]);

Результат:

javascript
{ entities: { users: { '10': { id: 10, name: 'Tim' } }, posts: { '1': { id: 1, title: 'React guide', author: 10 }, '2': { id: 2, title: 'Redux patterns', author: 10 } } }, result: ['1', '2'] }

Приклад у контексті React-компонентів

Без нормалізації:

javascript
function Post({ post }) { return ( <div> <h2>{post.title}</h2> <p>{post.author.name}</p> </div> ); }

Якщо оновиться ім'я автора, React перерендерить усі пости, тому що post.author - новий об'єкт у кожному.


З нормалізацією:

javascript
function Post({ postId }) { const post = useSelector(state => state.entities.posts[postId]); const author = useSelector(state => state.entities.users[post.authorId]); return ( <div> <h2>{post.title}</h2> <p>{author.name}</p> </div> ); }

Тепер оновлення author.name торкнеться лише тих компонентів, які залежать від authorId, а не всього списку постів.


Додаткові переваги нормалізації

ПеревагаОпис
Проста структураЗавжди знаєш, де шукати дані
Легко оновлювати і видалятиЗмінюєш за ID, без складних вкладеностей
Чіткі зв'язки між сутностями«Один до багатьох», «багато до багатьох»
Сумісно з селекторамиЧудово працює з мемоізацією (useMemo, reselect)
Менше JSON parsing і diffingДостатньо поверхневого порівняння

Коли не варто нормалізувати

Надмірна нормалізація шкідлива, якщо:

  • Даних небагато (10-20 записів, проста форма);
  • Оновлення рідкісні й не зачіпають піддерева;
  • Структура даних статична (наприклад, список вкладок або просте меню).

Нормалізація потрібна там, де є взаємопов'язані дані та багато оновлень.


Підсумок

Що робитьНавіщо потрібно
Зберігає дані «плоско» (за ID)Позбавляє від дублювання
Зберігає зв'язки через IDДозволяє оновлювати лише потрібні сутності
Зменшує кількість ререндерівПідвищує продуктивність
Робить логіку простішоюДані стають передбачуваними
Працює як міні-база данихЛегко оновлювати, шукати і кешувати

State normalization = база даних усередині React-стану.

Одне джерело істини для кожної сутності: менше ререндерів, менше багів, вища продуктивність.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.