Last active
          October 28, 2025 21:33 
        
      - 
      
- 
        Save sunmeat/8503dc901e4c65036fa5b41658ce10a0 to your computer and use it in GitHub Desktop. 
    simple redux example
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | App.jsx: | |
| // імпортуємо хуки та компонент Provider з react-redux | |
| import {useSelector, useDispatch, Provider} from 'react-redux' | |
| // !!! npm install react-redux @reduxjs/toolkit !!! | |
| // хук useSelector дозволяє отримати доступ до стану сховища - єдиного центру даних для всього додатка | |
| // у сховищі (store) зазвичай лежить один великий об'єкт - дерево стану, для всього | |
| // useSelector "селектить" (вибирає) потрібний шматок даних із цього глобального стану | |
| // і підписує компонент на оновлення вибраної частини стану | |
| // компонент буде перемальовано, коли вибраний стан зміниться | |
| // хук useDispatch повертає функцію dispatch, за допомогою якої можна відправляти дії (actions) у сховище | |
| // через dispatch запускаються зміни стану, описані в редьюсерах | |
| // вважається, що це основний спосіб взаємодії компонентів із Redux-станом | |
| // провайдер - це компонент, що обгортає весь додаток | |
| // він робить Redux store доступним для всіх вкладених компонентів через контекст | |
| // без нього хуки useSelector і useDispatch працювати не будуть, а компоненти не зможуть читати або змінювати глобальний стан | |
| // це обов'язковий міст між Redux і React | |
| // імпортуємо функції для створення слайса і сховища з redux toolkit | |
| import {configureStore, createSlice} from '@reduxjs/toolkit' | |
| // configureStore - це функція з Redux Toolkit, яка спрощує створення Redux store | |
| // це більш сучасна і зручна заміна застарілому в серпні 2022 року createStore | |
| // вона автоматично налаштовує devtools, middleware та інтеграцію з thunk | |
| // devtools - інструмент для відстеження дій і станів у браузері | |
| // middleware - функції-перехоплювачі, які обробляють дії між dispatch і reducer | |
| // thunk - це різновид middleware, корисний для написання асинхронних дій (наприклад, API-запитів) | |
| // взагалі, thunk ("глухий звук") - у програмістів означає шматок коду, який виконує певну відкладену роботу https://daveceddia.com/what-is-a-thunk/ | |
| // слайс (slice) - це "шматок" глобального стану та логіки, що до нього відноситься | |
| // він включає початковий стан, редюсери та згенеровані дії | |
| // кожен слайс відповідає за свою ізольовану частину бізнес-логіки (наприклад, лічильник, користувач, кошик тощо) | |
| // функція createSlice допомагає описати частину стану (слайс), редюсери та дії одночасно | |
| // вона створює і дії, і редьюсери автоматично, що скорочує обсяг коду | |
| // це основний спосіб роботи з Redux Toolkit | |
| import './App.css' | |
| // створюємо слайс (шматок стану) з ім'ям 'counter' | |
| // createSlice створює об'єкт з двома важливими властивостями: actions і reducer | |
| const counterSlice = createSlice({ | |
| name: 'counter', // ім'я слайса, використовується для генерації типів дій | |
| initialState: {count: 0}, // початковий стан лічильника | |
| reducers: { | |
| // функція-редьюсер для дії increment | |
| increment: (state) => { | |
| state.count += 1 // збільшуємо значення лічильника | |
| }, | |
| decrement: (state) => { | |
| state.count -= 1 // зменшуємо лічильник на 1 | |
| }, | |
| }, | |
| }) | |
| // витягуємо дію increment із створеного слайса | |
| const {increment, decrement} = counterSlice.actions | |
| // навіщо витягувати? основна причина - чистота коду і читабельність | |
| // написати далі по коду dispatch(increment()) буде простіше, ніж dispatch(counterSlice.actions.increment()) | |
| // і одразу зрозуміло, що викликається дія increment | |
| // створюємо сховище Redux з редьюсером із слайса | |
| const store = configureStore({ | |
| reducer: counterSlice.reducer, // підключаємо редюсер до сховища | |
| }) | |
| // createSlice упаковує окремі обробники дій із reducers в одну функцію counterSlice.reducer | |
| // якщо кілька слайсів, то буде reducer: { | |
| // counter: counterSlice.reducer, | |
| // anotherSlice: anotherSlice.reducer, | |
| // } | |
| // компонент, у якому використовується стан і дії Redux | |
| function Counter() { | |
| const count = useSelector((state) => state.count) // отримуємо значення лічильника із сховища | |
| const dispatch = useDispatch() // отримуємо функцію для відправки дій | |
| return ( | |
| <> | |
| <h1>Redux Toolkit</h1> | |
| <div className="card"> | |
| <button onClick={() => dispatch(decrement())}> | |
| зменшити | |
| </button> | |
| <button onClick={() => dispatch(increment())}> | |
| збільшити | |
| </button> | |
| <p>значення лічильника {count}</p> | |
| </div> | |
| </> | |
| ) | |
| } | |
| // тут обов'язково обгортаємо Counter у Provider | |
| function App() { | |
| return ( | |
| <Provider store={store}> {/* передаємо сховище всім дочірнім компонентам */} | |
| <Counter/> | |
| </Provider> | |
| ) | |
| } | |
| // redux - це централізоване сховище стану додатка, | |
| // і щоб компоненти могли отримати доступ до цього стану або змінити його, їм потрібно знати, де цей store | |
| // напряму прокидати store через пропси у всі компоненти - це складно і марнування часу, | |
| // особливо якщо компонентів багато і вони вкладені глибоко один в одного | |
| // тому React Redux використовує контекст (React Context API), щоб "прокинути" store на самий верх | |
| // і дати можливість будь-якому вкладеному компоненту отримати до нього доступ незалежно від рівня вкладеності | |
| // провайдер приймає store у пропсі і через контекст робить це сховище доступним для всіх нащадків | |
| // жоден компонент не отримує store напряму через пропси - натомість вони "підписуються" на контекст | |
| // і за допомогою хуків useSelector і useDispatch працюють із сховищем | |
| // хто "чекає" цей store? - усі компоненти, які використовують: | |
| // useSelector - щоб вибрати частину стану зі store | |
| // useDispatch - щоб відправляти дії (actions) у store | |
| // під капотом ці хуки звертаються до React Context, створеного <Provider>, щоб отримати екземпляр store | |
| // без <Provider> хуки просто не зможуть знайти і використовувати сховище, і додаток зламається | |
| export default App | |
| ========================================================================================================== | |
| App.css: | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| color: #f0f0f0; | |
| height: 100vh; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-bottom: 1rem; | |
| font-weight: 700; | |
| letter-spacing: 2px; | |
| text-shadow: 0 0 8px rgba(255, 255, 255, 0.7); | |
| } | |
| .card { | |
| background: rgba(255, 255, 255, 0.1); | |
| padding: 2rem 3rem; | |
| border-radius: 15px; | |
| box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 1.5rem; | |
| min-width: 320px; | |
| } | |
| button { | |
| background: #764ba2; | |
| color: #fff; | |
| border: none; | |
| padding: 0.6rem 1.5rem; | |
| font-size: 1.1rem; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: background 0.3s ease, transform 0.15s ease; | |
| box-shadow: 0 4px 12px rgba(118, 75, 162, 0.5); | |
| user-select: none; | |
| } | |
| button:hover { | |
| background: #5e3880; | |
| transform: scale(1.05); | |
| box-shadow: 0 6px 18px rgba(94, 56, 128, 0.7); | |
| } | |
| button:active { | |
| transform: scale(0.95); | |
| box-shadow: 0 3px 10px rgba(94, 56, 128, 0.6); | |
| } | |
| p { | |
| font-size: 1.3rem; | |
| font-weight: 700; | |
| letter-spacing: 1px; | |
| margin: 0; | |
| text-shadow: 0 0 6px rgba(255, 255, 255, 0.6); | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment