Що таке Редукс

Що таке Редукс



Основи Redux для початківців



Redux - Це інструмент для управління станом програми. Побудований на принципах технології Flux та функціонального програмування. Створений компанією FaceBook, але всупереч поширеній думці може використовуватися не тільки у зв'язці з React, але також з іншими фреймворками/бібліотеками.



Flux – це тип архітектури та набір патернів проектування веб-додатків. Детальніше на Wiki



Redux використовує методологію flux. Вона складається з 4 понять:





  • Інтерфейс користувача (View) - у React це компоненти


  • Сховище (Store)


  • Диспатчер


  • Action




У React за замовчуванням немає якогось глобального state (стану), який був би доступний у всьому додатку. Ви можете лише зберігати дані в межах одного компонента. Наприклад, у вас є інтернет-магазин і в ньому є кошик з товарами. Якщо працювати тільки зі стейтом компонента Кошик, то ці дані будуть недоступні в інших компонентах. Також, наприклад, у вас є іконка кошика в кутку екрана, яка повинна показувати кількість товару, які користувач додав туди. Так от засобами чисто React, це буде складно реалізувати.



Саме тому є такі бібліотеки як Redux, для зберігання всіх даних програми в одному місці та зручного їх оновлення.



Основні поняття Redux



Як я вже писав вище, основні поняття редаксу actions, dispatcher, store.



Store - Це стан веб-компонента, який зберігає в собі всю інформацію (або ту, яку ви вирішили зберегти в нього). Надалі сторінка буде доступна з будь-якого компонента вашої програми.



Action - Дія, що визначає що потрібно зробити. Відповідно до принципів функціонального програмування, ми не можемо змінювати об'єкт безпосередньо, тому нам потрібні екшени, щоб передати їх у диспатчер і «сказати», що потрібно зробити.



Dispatcher — повідомляє сховищу про якусь дію (action) та передає йому оновлену інформацію.



Тепер коли ми розібрали основні поняття, давайте подивимося, як працює Redux:



Компонент генерує дію (action), диспатчер повідомляє про це сховище (store), сховище змінює стан і дані передаються компонент (View).



Є ще одне поняття у Redux – це reducer (редюсер). Редюсер – це чиста функція, яка приймає як аргумент сховище та екшен. Основні правила редюсерів:





  • У цих функціях повинно бути «side effects» (побічних ефектів). Наприклад, не можна робити API запит для отримання будь-яких даних


  • Вони не повинні мутувати (змінювати) прийняті аргументи чи стан.


  • Не можна викликати нечисті функції всередині редюсерів (наприклад, Date.now() або Math.random())




Докладніше про чисті функції можна прочитати тут.



Простий приклад використання Redux



Тепер на простому практичному прикладі розберемо, як працювати з Redux.



Ми зробимо простий додаток ToDo, який дасть можливість створювати свої таски зі збереженням їх у store. Це буде простий додаток для прикладу, основний наголос зроблений на роботу з Redux.



Отже, є два варіанти, ви можете завантажити стартовий проект і просто запустити установку, або покроково пройти і створити проект зі старту.



Встановлення та налаштування проекту



Щоб створити програму заново, відкриваємо командний рядок або Git Bash



npx create-react-app redux-first-app


Далі заходимо в папку проекту та встановлюємо Redux та пакет для Реакту – react-redux



cd redux-first-app/ // Потім npm i redux react-redux


Якщо ви завантажили архів із вже готовим додатком, тоді його потрібно розпакувати, увійти в папку з додатком та в командному рядку/терміналі запустити команду:



Тепер, щоб запустити наш проект, потрібно скористатися наступною командою:



Проект буде зібраний та запущений, автоматично відкриється вкладка у браузері



Результат виконання команди npm run start



Для того, щоб не верстати все знову, ми використовуємо Bootsrap. Давайте його встановимо.



npm install react-bootstrap bootstrap


Також підключимо стилі у файлі src/index.js



import React from 'react'; import ReactDOM від 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals від './reportWebVitals'; import 'bootstrap/dist/css/bootstrap.min.css'; ReactDOM.render(  , document.getElementById('root') ); reportWebVitals();


Створення базової структури для сховища



Тепер зробимо базову структуру для Redux. Створимо папку src/store, а в ній 4 файли



Спочатку визначимо, які типи екшенів нам потрібні у файлі actionTypes.js. Можна типи і не визначати, але надалі це дасть нам змогу скоротити час на дебагінг, якщо раптом знадобиться змінити ім'я екшену, всі вони знаходяться в одному місці, що теж зручно. Якщо нам знадобиться екшен в іншому місці, нам буде достатньо імпортувати його в іншому модулі.



У нашому додатку, наприклад, нам потрібен буде екшен у 2 файлах: actions та reducer. Створимо файл actionTypes.js і в ньому визначимо наші типи:



export const TASK_ADD = 'TASK_ADD'; export const TASK_TOGGLE = 'TASK_TOGGLE'; export const TASK_REMOVE = 'TASK_REMOVE';


У файлі store/actions.js ми опишемо всі екшени, які нам потрібні для застосування:



import * as actions from './actionTypes'; export const addTask = task => (<type: actions.TASK_ADD, payload: task>); export const toggleTask = (<type: actions.TASK_TOGGLE, payload:<id>>); export const removeTask = (< type: actions.TASK_REMOVE, payload: < id >>)


Вище ви бачите типову структуру екшену: це функція, яка повертає об'єкт із двома властивостями:





  • type - Тип екшену (ми його визначали в actionTypes)


  • payload - дані, які нам потрібно передати до редюсера




Тепер розглянемо функцію редюсер (store/reducer.js):



import * as actions from './actionTypes'; let lastId = 0; export default function reducer(state = [], action) < switch (action.type) < case actions.TASK_ADD: return [.state, < id: ++lastId, title: action.payload.title, completed: false, >]; case actions.TASK_TOGGLE: return state.map(task => < if (task.id === action.payload.id) return < . task, completed: !task.completed >return task; >); case actions.TASK_REMOVE: return state.filter(task => action.payload.id !== task.id); default: return state; > >


Тут ми імпортуємо наші типи екшенів, потім визначаємо змінну для того, щоб задавати ID кожному новому таску.



Сам reducer приймає як аргументи state (або дорівнює порожньому масиву) і екшен. Далі ми перевіряємо тип екшену і залежно від цього робимо певні маніпуляції зі стейтом.



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



Далі на підставі цього редюсера нам потрібно створити store за допомогою функції createStore. Створимо файл store.js з таким вмістом:



import < createStore > від 'redux'; import reducer from "./reducer"; const store = createStore( reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); export default store;


* У мене також другим параметром додано слід. рядок



window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()


Це для роботи плагіна для Chrome – Redux DevTools. Зручний плагін для дебагінгу.



Тепер після створення store, ми можемо використовувати його у будь-якому модулі нашої програми.



Основні методи роботи зі store





  • store.dispatch() - Диспатч будь-якого екшену


  • store.getState() - Отримання даних, які зберігаються в store


  • store.subscribe() - Підписка на зміни store.




Redux у функціональних компонентах (хукі)



Наш додаток буде побудовано за допомогою функціональних компонентів та хуків, тому ми трохи розглянемо, які хуки надає нам Redux для роботи в таких компонентах.





  • useDispatch() — заміна mapDispatchToProps(). Цей хук повертає метод dispatch.За його допомогою ми потім можемо диспатчити потрібні екшени.


  • useSelector() — аналог mapStateToProps() — Цей хук приймає колбек, який як аргумент приймає поточний стан. Ви можете повернути весь state або певні дані з нього.


  • useStore() - цей хук повертає посилання на той самий state, який був переданий в . У документації редаксу йдеться про те, що краще цей хук не використовувати часто, а краще useSelector()




Тепер давайте повернемося до нашої програми. В index.js нам потрібно обернути нашу програму в компонент Provider і передати йому store через пропси. Store ми створили у файлі store/store.js



import React from 'react'; import ReactDOM від 'react-dom'; import < Provider >from 'react-redux'; import './index.css'; import App from './App'; import reportWebVitals від './reportWebVitals'; import 'bootstrap/dist/css/bootstrap.min.css'; import store from './store/store'; ReactDOM.render(  >   , document.getElementById('root') ); reportWebVitals();


Наступним кроком давайте створимо папку, в якій зберігатимемо наші компоненти і назвемо її componetns. У ній створимо 3 файли:





  • Task.js — цей компонент відповідатиме за виведення окремого тяга


  • TaskList.js - це буде список тяган


  • AddNewTask.js — а цей компонент відповідатиме за створення нового тяга




import React від "react"; import < useDispatch >з "react-redux"; import < Form, ListGroup >з "react-bootstrap"; import < toggleTask, removeTask >з "../store/actions"; const Task = (< task >) => < const < id, title, completed >= task; const dispatch = useDispatch(); // Отримуємо диспатч із хука return (  > checked= onChange= < () =>dispatch(toggleTask(id)) > // диспатчім потрібний екшен під час кліку по тяганню  
dispatch(removeTask(id))>>Видалити // Диспатчі екшен removeTask для видалення тяга зі стору
) > export default Task;


Спочатку імпортуємо хук useDispatch(), т.к.у цьому компоненті ми будемо диспатчити 2 екшени: виконання таска (toggleTask) та видалення (removeTask). У компоненті у нас є подія onChange - при кліку на цей компонент ми будемо диспатчити екшен для перемикання стану таска, ну а при кліку кнопки видалити - диспатчім екшен для видалення таска з нашого стору.



Далі файл src/components/TaskList.js



import React from 'react'; import < ListGroup >з "react-bootstrap"; import Task from './Task'; // імпортуємо компонент таска, створений раніше const TaskList = (< tasks >) => < if (tasks.length) return (  < // пробегаемся методом map по нашему массиву с тасками и выводим для каждый таск tasks.map(task => task= /> ) > ) else return null; > export default TaskList;


Тепер останній компонент AddNewTask.js



import React, < useState > from 'react'; import < Button, FormControl, InputGroup >з "react-bootstrap"; import * as actions from "../store/actions"; import < useDispatch >з "react-redux"; const AddNewTask = () => < const [taskTitle, setTaskTitle] = useState(''); const dispatch = useDispatch(); const handleTaskTitleChange = (e) => < setTaskTitle(e.target.value); >const handleTaskSubmit = () => < dispatch(actions.addTask(< title: taskTitle >)); setTaskTitle(''); > return (  onChange=handleTaskTitleChange(e)> /> >Зберегти   ) > export default AddNewTask;


Тут у нас буде 2 обробники handleTaskTitleChange() та handleTaskSubmit(). Останній диспатчитиме екшен для створення нового тяга. В ідеалі, тут ще додати перевірку на порожній рядок і обрізати зайві прогалини, але у нас не про це зараз 🙂



Тепер залишився заключний крок, змінити файл scr/App.js та додати трохи стилів



import React from 'react'; import < Container, Col, Row >з "react-bootstrap"; import TaskList from "./components/TaskList"; import AddNewTask from "./components/AddNewTask"; import < useSelector >from "react-redux"; import './App.css'; function App() < // Отримуємо наш state const tasks = useSelector(state =>state); return (      > 

Список завдань

/>
); > export default App;


.main-app-container .list-group-item < display: flex; >.list-group-item .form-check < width: 90%; >.list-group-item-actions < width: 10%; text-align: right; >.list-group-item-actions span .main-app-container .list-group-item:hover .list-group-item-actions span < display: inline; cursor: pointer; >.list-group-item-actions span:hover < text-decoration: underline; >.list-group-item.task-completed < background-color: #f2f2f2; >.list-group-item.task-completed .form-check-label

У результаті у нас вийшов такий додаток



Ваші запитання та коментарі:



Свіжі записи



Для чого та коли використовується Redux



У контексті сучасної розробки, де складність веб-додатків тільки зростає, Redux виступає як надійний партнер, полегшуючи керування даними, забезпечуючи передбачуваність та покращуючи тестованість коду. У наступних розділах ми більш докладно розглянемо, що таке redux, що він є і чому він вартий вашої уваги.



Що таке?



Redux - це JavaScript-бібліотека, покликана спростити керування станом вашої веб-програми. Її основне призначення полягає в тому, щоб зробити керування даними більш організованим та передбачуваним.



У центрі концепції Redux знаходиться сховище стану (Store). Це своєрідне сховище, де зібрані всі дані вашої програми. Однак важлива відмінність від традиційного підходу полягає в тому, що Redux пропонує єдине централізоване сховище, доступне для всіх компонентів вашої програми. Це як загальний банк даних, якого можна звернутися з будь-якої точки докладання.



Отже, цей інструмент дозволяє нам ефективно управляти даними, роблячи процес розробки організованішим і передбачуваним.



Принцип того, як працює redux, ґрунтується на таких концепціях:





  • Application state: це об'єкт, який містить усі дані, необхідні для роботи програми.


  • Actions: це об'єкти, які репрезентують зміни стану програми.


  • Reducers: це функції, які визначають, як стан програми змінюється у відповідь дії.




Чому варто використати?



Чому використання Redux - це саме те, що може зробити ваше життя розробника простіше і більш передбачуваним?



Перша важлива причина – це спрощення керування станом вашої програми. Ви, напевно, стикалися з ситуаціями, коли дані повинні бути доступні в різних частинах програми. Замість того, щоб передавати ці дані через безліч компонентів, Redux надає централізоване сховище, яке можна використовувати з будь-якої точки вашої програми. Це особливо цінно, коли вам потрібно обмінюватись даними між різними компонентами. Уявіть це як загальний ресурс, до якого ви маєте доступ у будь-який момент.



Але це ще все. Він приносить нам передбачуваність та тестованість нашого коду. Тут справа в тому, що всі зміни стану відбуваються через Actions та Reducers. Нічого не відбувається раптово та несподівано. Ми точно знаємо, які дії викликаються та які редьюсери обробляють ці зміни. Це робить процес налагодження та тестування набагато більш простим та передбачуваним.



Коли потрібно його використовувати?



Redux варто використовувати, коли:





  • Програма має складний стан/велику кількість даних, які необхідно відстежувати;


  • додаток вимагає централізованого керування станом;


  • програма вимагає реактивного стану.




Однак варто пам'ятати, що Redux не підходить для всіх програм. У деяких випадках може додати надмірну складність.



Інструмент має ряд переваг, але також деякі недоліки:



Переваги:





  • передбачуваність: забезпечує чітку структуру керувати станом, що робить код зрозумілішим;


  • тестування: завдяки суворим правилам зміни стану спрощує написання тестів для коду;


  • управління глобальним станом: Цей інструмент добре справляється з керуванням глобальним станом програми, що робить доступ до даних легким і ефективним.




Недоліки:





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




  • додає додаткові шари абстракції: це може уповільнити початкову розробку та ускладнити процес навчання нових розробників;




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




Важливо оцінити потреби вашого проекту: для невеликих і простих програм цей інструмент може здатися зайвим, але у разі складних додатків з безліччю компонентів і складним глобальним станом він може значно покращити організацію коду та забезпечити легкість його супроводу.



Основні компоненти



Redux спирається на три ключові компоненти для керування станом програми: Store, Actions та Reducers. Давайте розглянемо кожен із них докладніше.



Store (сховище) є центральним компонентом Redux. Це об'єкт, який містить глобальний стан вашої програми. Роль Store полягає в тому, щоб зберігати та надавати доступ до даних, які вашому додатку необхідні. Store є деревоподібною структурою даних, де кожна частина стану має свій шлях (схожий на шлях до файлу у файловій системі). Це означає, що доступ до даних здійснюється через ключі і кожен ключ вказує на конкретну частину стану.



Actions є об'єктами, які описують події або сигнали. Вони повідомляють, що щось сталося у вашому додатку і служать для ініціювання змін стану Redux.



⚡ Готові поринути у світ Front End розробки?



🌐 З нашим онлайн курсом Front End навчайтеся будь-де і будь-коли!



🚀 Переконайтеся, що Front End є вашим покликанням протягом 7 днів тестового періоду.



👨‍🏫 Професійні ментори завжди готові допомогти вам.



Redux для новачків: база, з якої можна стартувати



Сьогодні розглянемо бібліотеку Redux для JS, навіщо вона потрібна, і чи варто вона вашої уваги. Redux – це бібліотека для керування станом програми. Redux створений для тих випадків, коли:





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


  • Ці дані потрібно нишпорити між компонентами, що знаходяться на різних рівнях ієрархії.


  • Є складна логіка оновлення даних і хочеться, щоб код цієї логіки був не просто працюючим, а й зрозумілим через півроку.






  1. Впорядкувати дані.


  2. Спростити їх доступ із будь-якої точки програми.


  3. Стандартизувати логіку зміни даних.




Головний принцип Redux - одне джерело правди. Всі дані програми зберігаються в одному місці - в store. Якщо хочеться щось змінити:





  1. Ви диспатчіть action (Опис того, що має відбутися).


  2. Дані оновлюються через чисту функцію reducer (Чисту - значить без побічних ефектів).


  3. Новий стан стає доступним всім компонентів.




Найчастіше Redux використовується у зв'язці з React, і це не дивно – react-redux робить їхню спільну роботу неймовірно зручною. Але при цьому Redux цілком може працювати з іншими фреймворками (або навіть без них).



Основний функціонал Redux



Для початку встановимо Redux та його дружка - react-redux :



npm install redux react-redux


redux – це ядро ​​бібліотеки. React-redux — це набір інструментів для інтеграції Redux з React.



Створення Store



Почнемо з головного - store. Це центральне сховище стану. Все, що ви зберігатимете, знаходиться тут:



import < createStore > від 'redux'; // Початковий стан const initialState = < counter: 0, >; // Ред'юсер - чиста функція, яка оновлює стан function counterReducer(state = initialState, action) < switch (action.type) < case 'INCREMENT': return < . state, counter: state.counter + 1>; case 'DECREMENT': return < . state, counter: state.counter - 1>; default: return state; > > // Створюємо store const store = createStore(counterReducer); console.log(store.getState()); //


Редьюсер отримує поточний стан та дію (action) і повертає новий стан.



Actions: кажемо, що робити



Action – це просто об'єкт із обов'язковим полем type . Приклад:



const incrementAction = <type: 'INCREMENT'>; const decrementAction = <type: 'DECREMENT' >;


Кожна дія каже редьюсерові: «Давай щось зробимо».



Reducer



Ось редьюсер із нашого прикладу:



function counterReducer(state = initialState, action) < switch (action.type) < case 'INCREMENT': return < . state, counter: state.counter + 1>; case 'DECREMENT': return < . state, counter: state.counter - 1>; default: return state; > >




  • state – поточний стан.


  • action – що ми хочемо зробити.


  • Ред'юсер повинен повернути новий стан. Якщо дія не розпізнана, повертаємо стару.




Підключення React та Redux



Настав час об'єднати Redux із React. Це простіше, ніж здається завдяки react-redux :



Provider робить store доступним для всіх компонентів:



import React from 'react'; import ReactDOM від 'react-dom'; import < Provider >from 'react-redux'; import < createStore > від 'redux'; import counterReducer from './reducers'; const store = createStore(counterReducer); ReactDOM.render( > , document.getElementById('root') );


Тепер підключаємо хуки useSelector і useDispatch і будь-який компонент зможе отримувати дані зі store через useSelector і відправляти дії через useDispatch :



import React from 'react'; import < useSelector, useDispatch >from 'react-redux'; function Counter() < const counter = useSelector((state) =>state.counter); const dispatch = useDispatch(); return ( 
Counter:
); > export default Counter;


Redux Toolkit



Ванільний Redux вимагає багато шаблонного коду: окремі екшени, ред'юсери, константи. Все це звучить трохи стомлюючим. Ось чому з'явився Redux Toolkit. Це набір інструментів, який значно спрощує роботу і саме їм користуються при роботі з Redux на сьогоднішній день.



З Redux Toolkit можна:





  1. Створювати редьюсери та екшени в одній функції createSlice.


  2. Позбутися ручного керування станом через Immer.js, вбудований у Toolkit.


  3. Спрощувати налаштування store через configureStore.




import < configureStore, createSlice >from '@reduxjs/toolkit'; // Створюємо slice (ред'юсер + екшени) : (state) => < state.value -= 1; > incrementByAmount: (state, action) => < state.value += action.payload; // Екшен export const < increment, decrement, incrementByAmount >= counterSlice.actions; // Store const store = configureStore(< reducer: < counter: counterSlice.reducer, >, >); export default store;


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



Докладніше про Toolkit можна глянути тут.



Middleware



Одна з найпотужніших, але недооцінених на мій погляд властивостей Redux – це middleware. По суті, це функції, що сидять між екшенами та ред'юсерами, і можуть перехоплювати дії, додавати додаткову логіку або навіть модифікувати екшени під час їхньої дії.



У Redux middleware застосовуються через функцію applyMiddleware:



import < createStore, applyMiddleware >from 'redux'; import logger from 'redux-logger'; const store = createStore(rootReducer, applyMiddleware(logger));


redux-logger виводить інформацію про кожен екшен та стан у консоль.



Асинхронність та Thunk



Redux по дефолту синхронний, але для роботи з асинхронними операціями, наприклад, запитами до API, є спеціальне middleware redux-thunk :



npm install redux-thunk


import < createStore, applyMiddleware >from 'redux'; import thunk from 'redux-thunk'; const store = createStore(rootReducer, applyMiddleware(thunk));


А тепер створимо асинхронний екшен:



// actions/userActions.js export const fetchUsers = () => async (dispatch) => < dispatch(< type: 'FETCH_USERS_REQUEST' >); try < const response = await fetch('https://jsonplaceholder.typicode.com/users'); const data = await response.json(); dispatch(< type: 'FETCH_USERS_SUCCESS', payload: data >); > catch (error) < dispatch(< type: 'FETCH_USERS_FAILURE', payload: error.message >); > >;


Тепер Redux може опрацьовувати складні асинхронні сценарії.



Тепер перейдемо до практики.



Приклад застосування бібліотеки



Уявимо, що є інтернет-магазин, що спеціалізується на товарах для котиків: іграшки, корм, лежанки, лазилки і все, що може зробити щасливим пухнастого клієнта. Нам потрібно керувати такими станами програми:





  1. Список товарів: завантаження з API та відображення на сторінці.


  2. Кошик: додавання та видалення товарів.


  3. Авторизація користувача: щоб дозволити зареєстрованим користувачам оформляти замовлення


  4. Оформлення замовлення: управління даними для оплати та доставки.




Щоб зробити програму масштабованою та підтримуваною, розіб'ємо стан на кілька модулів: products, cart, auth, order. Кожен модуль представлятиме свою «частину стану» (state slice) і працюватиме через Redux Toolkit.



Підготовка стану товарів



Спочатку налаштуємо модуль для роботи з товарами. Допустимо, ми завантажуємо список товарів із сервера.



Slice для товарів:



import < createSlice, createAsyncThunk >from '@reduxjs/toolkit'; // Асинхронний thunk для завантаження товарів export const fetchProducts = createAsyncThunk('products/fetchProducts', async() => < const response = await fetch('https://api.example.com/cat-products'); const data = await response.json(); const productsSlice = createSlice(< name: 'products', initialState: < items: [], status: 'idle', // idle | loading | succeeded | failed error: null, >, reducers: <>, extraReducers: (builder ) => < Builder. ; state.items = action.payload; > .addCase(fetchProducts.rejected, (state, action) => < state.status = 'failed'; state.error = action.error.message; >); ); export default productsSlice.reducer;


Тепер є асинхронний екшен fetchProducts, який завантажує товари та оновлює стан.



Управління кошиком



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



Slice для кошика:



import < createSlice >from '@reduxjs/toolkit'; const cartSlice = createSlice(< name: 'cart', initialState: < items: [], // [< id, name, price, quantity >] totalItems: 0, totalPrice: 0, >, reducers: < addToCart: (state , action) => < const product = action.payload; const existingItem = state.items.find((item) =>item.id === product.id); >else < state.items.push(< . product, quantity: 1 >); > state.totalItems += 1; state.totalPrice += product.price; = action.payload; const existingItem = state.items.find((item) =>item.id === productId); < state.totalItems -= existingItem.quantity; state.totalPrice -= existingItem.price * existingItem.quantity; updateQuantity: (state, action) => < const < id, quantity >= action.payload; const existingItem = state.items.find((item) => item.id === id); quantityDiff = quantity - existingItem.quantity; existingItem.quantity = quantity; state.totalItems += quantityDiff; state.totalPrice += quantityDiff *existingItem.price; >>, >, >); export const < addToCart, removeFromCart, updateQuantity >= cartSlice.actions; export default cartSlice.reducer;


Авторизація користувача



Авторизація потрібна для оформлення замовлення та збереження історії покупок. Будемо зберігати інформацію про поточного користувача в модулі auth.



Slice для авторизації:



import < createSlice, createAsyncThunk >from '@reduxjs/toolkit'; export const login = createAsyncThunk( 'auth/login', async (credentials) => < const response = await fetch('https://api.example.com/login', < method: 'POST', body: JSON). stringify(credentials), headers: < 'Content-Type': 'application/json' >, >), const data = await response.json(); const authSlice = createSlice(< name: 'auth', initialState: < user: null, token: null, status: 'idle', error: null, >, reducers: < logout: (state) =>< state.user = null; state.token = null; >, >, extraReducers: (builder) => < builder. , (state, action) => < state.status = 'succeeded'; ) => < state.status = 'failed'; export const < logout >= authSlice.actions; export default authSlice.reducer;


Оформлення замовлення



Після вибору товарів та авторизації відправляємо дані замовлення на сервер.



Slice для замовлення:



import < createSlice, createAsyncThunk >from '@reduxjs/toolkit'; export const submitOrder = createAsyncThunk( 'order/submitOrder', async (orderDetails, < getState >) => < const < token >= getState().auth; const response = await fetch('https://api.example.com /orders', < method: 'POST', body: JSON.stringify(orderDetails), headers: < 'Content-Type': 'application/json', Authorization: `Bearer $`, >, >); .json(); > ); const orderSlice = createSlice(< name: 'order', initialState: < status: 'idle', error: null >, reducers: <>, extraReducers: (builder) => < builder .addCase(submitOrder.pending, (state) =>< state.status = 'loading'; >) .addCase(submitOrder.fulfilled, (state) => < state.status = 'succeeded'; >) .addCase(submitOrder.rejected, (state, action) => < state.status = 'failed'; export default orderSlice.reducer;


І ось так, крок за кроком ми побудували інтернет-магазин для котиків, який може впоратися з будь-яким капризом пухнастих клієнтів: від кошика до оформлення замовлення. Redux став сполучною ланкою між усіма частинами нашого додатка – управління товарами, авторизація, обробка замовлень – все чітко та передбачувано. Завдяки Redux Toolkit обійшлися без тонни шаблонного коду.



Що в результаті



Redux – штука потужна, але не панацея. Він ідеальний, якщо у вас складна програма з купою станів, якими потрібно керувати централізовано. Далі річ за вами: експериментуйте, пробуйте різні підходи, але не забувайте, що Redux потрібний не завжди. Іноді і Context API за очі вистачить.



Якщо хочеться копнути глибше:





  • FAQ Redux: https://redux.js.org/faq


  • Redux Toolkit: https://redux‑toolkit.js.org/


  • React‑Redux: https://react‑redux.js.org/




Що ще вивчити? Розберіться з redux-thunk та redux-saga для асинхронщини, гляньте Reselect для оптимізації селекторів. І обов'язково пограйтеся з Redux DevTools.



Діліться своїм досвідом роботи з Redux та порадами для початківців!





  • 4 грудня: Створення веб-компонентів та використання Shadow DOM. Дізнатись детальніше


  • 18 грудня: Управління станом із Pinia для Vue3. Дізнатись детальніше


Схожі записи