Філософія Redux та Три Принципи
Філософія Redux та Три Принципи
Redux часто вважають складною бібліотекою, але насправді він базується на кількох дуже простих ідеях. Складність виникає не з самої бібліотеки, а з нових термінів та обмежень, які вона накладає.
Але ці обмеження існують не просто так. Вони — це те, що робить ваш код передбачуваним.
Що таке Redux?
Формально: Redux — це контейнер передбачуваного стану для JavaScript-додатків.
Це означає, що:
- Він зберігає дані (контейнер).
- Дані змінюються передбачувано (ми точно знаємо, хто, коли і як їх змінив).
- Він не прив'язаний до React (можна використовувати з Angular, Vue, або навіть vanilla JS).
Історично Redux був створений Dan Abramov та Andrew Clark у 2015 році як реалізація архітектури Flux (від Facebook), але спрощена і покращена ідеями з мови Elm.
Три Принципи Redux
Уся "магія" Redux тримається на трьох китах. Якщо ви зрозумієте їх, ви зрозумієте Redux.
1. Єдине джерело правди (Single Source of Truth)
Весь стан вашого додатку зберігається в дереві об'єктів всередині одного Store.
На відміну від Flux, де могло бути багато Store-ів, у Redux Store завжди один. Це як гігантський JSON-об'єкт, що описує весь ваш додаток.
// Приклад того, як виглядає Store всередині
const state = {
user: {
id: 1,
name: 'Ivan',
role: 'admin',
},
todos: [
{ id: 1, text: 'Вивчити Redux', completed: false },
{ id: 2, text: 'Написати код', completed: true },
],
visibilityFilter: 'SHOW_ALL',
}
Переваги:
- Легко зберігати стан на сервері та відновлювати його (SSR).
- Легко дебажити (весь стан в одному місці).
- Легко реалізувати функції на кшталт Undo/Redo.
2. Стан доступний лише для читання (State is Read-Only)
Єдиний спосіб змінити стан — це відправити (dispatch) Action (дію), об'єкт, що описує, що сталося.
Ви не можете написати state.user.name = 'Petro'. Це заборонено. Замість цього ви кажете системі: "Гей, користувач хоче змінити ім'я".
Це робиться через простий об'єкт:
// Action
{
type: 'UPDATE_USER_NAME',
payload: 'Petro'
}
Це гарантує, що ні потік з мережі, ні подія миші не можуть записати щось у стан безпосередньо. Усі зміни централізовані та відбуваються в строгому порядку.
3. Зміни вносяться чистими функціями (Changes are made with Pure Functions)
Щоб описати, як саме стан змінюється у відповідь на actions, ви пишете Reducers (редюсери).
Reducer — це просто функція, яка бере попередній стан і дію, а повертає новий стан.
// (PreviousState, Action) => NewState
function userReducer(state, action) {
if (action.type === 'UPDATE_USER_NAME') {
return {
...state,
name: action.payload,
}
}
return state
}
Важливо: Редюсер не змінює існуючий об'єкт state. Він створює новий об'єкт з оновленими даними. Це і є принцип Іммутабельності, про який ми поговоримо детальніше в наступному уроці.
Однонаправлений потік даних (Data Flow)
У Redux дані завжди рухаються в одному напрямку (Unidirectional Data Flow). Це відрізняє його від двостороннього зв'язування (Two-way data binding), яке було популярне в ранніх фреймворках (наприклад, AngularJS).
Життєвий цикл даних у Redux виглядає так:
Детальний розбір циклу:
- Подія: Щось трапляється в додатку (клік кнопки, прийшли дані з API).
- Dispatch: UI компонент відправляє Action в Store.
dispatch({ type: 'DEPOSIT', payload: 10 })
- Reducer: Store викликає функцію-редюсер, передаючи їй поточний стан і цей action.
reducer({ balance: 0 }, { type: 'DEPOSIT', payload: 10 })
- Update: Редюсер повертає новий стан.
return { balance: 10 }
- Re-render: Store зберігає новий стан і повідомляє всі підписані UI компоненти, що дані змінилися. Компоненти перемальовуються з новими даними.
Цей цикл робить поведінку програми надзвичайно передбачуваною. Якщо ви бачите неправильні дані на екрані, ви точно знаєте, що це сталося через якийсь конкретний Action, який був неправильно оброблений Reducer-ом.
Але чому так важливо "не змінювати" стан, а "створювати новий"? Чому не можна просто зробити state.value++? Про це — у наступному розділі про чистоту функцій.
Вступ до State Management
Перш ніж пірнати в код Redux, давайте зупинимося і відповімо на головне питання: "Яку проблему ми взагалі намагаємося вирішити?".
Чисті функції та Іммутабельність
Це, мабуть, технічно найважливіший розділ для розуміння того, як писати Redux код правильно. Більшість багів у початківців виникають саме через порушення цих правил.