Створення Store (Classic Redux)
Створення Store (Classic Redux)
Ми починаємо практичну частину з "класичного" Redux. Це саме той підхід, який використовувався до 2019 року. Хоча зараз рекомендовано використовувати Redux Toolkit, розуміння того, як працює createStore, є критичним для розуміння самої суті бібліотеки.
createStore в офіційній документації позначені як deprecated. Не лякайтеся. Вони не видалені, просто команда Redux наполегливо рекомендує використовувати Toolkit. Але для навчання ми почнемо саме з "бази".Встановлення
Для початку нам потрібен лише пакет redux. Ми поки що не підключаємо React.
npm install redux
Анатомія Store
Уявіть, що ви створюєте звичайний JavaScript файл store.js. Наше завдання — створити об'єкт, який буде зберігати число (лічильник).
1. Початковий стан (Initial State)
Спочатку визначимо, з чого ми починаємо.
const initialState = {
value: 0
};
2. Створення Reducer
Редюсер — це функція, яка приймає рішення, як змінити стан.
// (state, action) => newState
function counterReducer(state = initialState, action) {
// Ми перевіряємо "тип" дії
if (action.type === 'counter/increment') {
// Повертаємо НОВИЙ об'єкт стану
return { ...state, value: state.value + 1 };
}
if (action.type === 'counter/decrement') {
return { ...state, value: state.value - 1 };
}
// Дуже важливо! Якщо дія нам невідома, повертаємо старий стан без змін.
return state;
}
state = initialState. Коли Redux запускається вперше, він передає в редюсер undefined замість стейта. Цей параметр гарантує, що у нас буде початкове значення.3. Ініціалізація Store
Тепер використовуємо функцію createStore з бібліотеки redux.
import { createStore } from 'redux';
const store = createStore(counterReducer);
export default store;
Використання Store (Vanilla JS)
Щоб довести, що Redux не прив'язаний до React, давайте подивимося, як з ним працювати у звичайному JS скрипті.
У об'єкта store є 3 головні методи:
getState()
Повертає поточний стан.
console.log(store.getState());
// Output: { value: 0 }
dispatch(action)
Відправляє дію для зміни стану.
store.dispatch({ type: 'counter/increment' });
console.log(store.getState());
// Output: { value: 1 }
subscribe(listener)
Дозволяє підписатися на зміни. Функція-слухач буде викликатися щоразу, коли action був оброблений (dispatch завершився).
const unsubscribe = store.subscribe(() => {
console.log('Стан змінився!', store.getState());
});
store.dispatch({ type: 'counter/increment' });
// Logs: "Стан змінився! { value: 2 }"
store.dispatch({ type: 'counter/decrement' });
// Logs: "Стан змінився! { value: 1 }"
// Відписатися
unsubscribe();
Повний приклад коду
Зберемо все разом:
import { createStore } from 'redux';
const initialState = { value: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'counter/increment':
return { ...state, value: state.value + 1 };
case 'counter/decrement':
return { ...state, value: state.value - 1 };
default:
return state;
}
}
const store = createStore(counterReducer);
export default store;
import store from './store';
// UI елементи
const valueEl = document.getElementById('value');
const btnInc = document.getElementById('increment');
const btnDec = document.getElementById('decrement');
// 1. Функція рендеру UI на основі стану
function render() {
const state = store.getState();
valueEl.innerHTML = state.value.toString();
}
// 2. Підписуємось на зміни (render буде викликатись при кожному dispatch)
render(); // Перший рендер
store.subscribe(render);
// 3. Обробка подій UI -> Dispatch Action
btnInc.addEventListener('click', () => {
store.dispatch({ type: 'counter/increment' });
});
btnDec.addEventListener('click', () => {
store.dispatch({ type: 'counter/decrement' });
});
Це все! Це і є ядро Redux. Усе інше (React-Redux, Middleware, Toolkit) — це надбудови над цим простим патерном: Action -> Dispatch -> Reducer -> Store -> Subscribe.
Далі ми розглянемо, як структурувати код професійно, використовуючи Actions Constants та Creators.
Чисті функції та Іммутабельність
Це, мабуть, технічно найважливіший розділ для розуміння того, як писати Redux код правильно. Більшість багів у початківців виникають саме через порушення цих правил.
Actions, Constants та Action Creators
У попередньому прикладі ми писали об'єкти action "на місці" і використовували рядки 'counter/increment' прямо в коді. У великому проєкті це прямий шлях до помилок.