Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чим thunk відрізняється від звичайного action?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Звичайний action** - це **об'єкт**, який описує *що сталося* (наприклад: `{ type: 'INCREMENT', payload: 1 }`). **Thunk** - це **функція**, яка описує *що потрібно зробити* (наприклад: `dispatch -> API -> dispatch SUCCESS/ERROR`). **Ключове:** thunk має доступ до `dispatch`/`getState` і може відправляти інші actions, а звичайний action одразу йде в reducer.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротка відповідь > **Звичайний action** - це **об'єкт**, який описує *що сталося* > (наприклад: `{ type: 'INCREMENT', payload: 1 }`). > > **Thunk** - це **функція**, яка описує *що потрібно зробити* > (наприклад: `dispatch -> API -> dispatch SUCCESS/ERROR`). --- ## 1. Звичайний action Redux за своєю природою **синхронний**. Кожна дія - це **plain object** (простий об'єкт) з обов'язковим полем `type`: ```javascript const increment = { type: 'INCREMENT', payload: 1 } ``` Ти передаєш його в store: ```javascript store.dispatch(increment) ``` -> Redux одразу викликає reducer -> reducer синхронно повертає новий стан. Все просто і миттєво. --- ## 2. Thunk (асинхронний action) Thunk - це **функція, а не об'єкт**. Коли Redux бачить функцію, він сам по собі не знає, що з нею робити - тому в справу вступає **middleware redux-thunk**. ```javascript const fetchUser = (id) => { return async (dispatch, getState) => { dispatch({ type: 'USER_FETCH_START' }) const response = await fetch(`/api/users/${id}`) const data = await response.json() dispatch({ type: 'USER_FETCH_SUCCESS', payload: data }) } } ``` Тут **thunk - це "дія-процес"**, яка всередині себе: 1. виконує асинхронний код (API-запит), 2. і вже потім робить `dispatch` звичайних (синхронних) actions. --- ## 3. Порівняння в коді | Тип | Що це | Як виглядає | Що робить | |---|---|---|---| | **Звичайний action** | Об'єкт | `{ type: 'ADD_TODO', payload: 'Buy milk' }` | Одразу йде в reducer | | **Thunk** | Функція | `(dispatch, getState) => { ... }` | Виконує логіку (зазвичай асинхронну), потім dispatch'ить звичайні actions | --- ## 4. Приклад у дії ### Звичайний action: ```javascript dispatch({ type: 'LOGIN_SUCCESS', payload: user }) ``` Одразу оновить store. --- ### Thunk action: ```javascript dispatch(loginUser(credentials)) ``` ```javascript const loginUser = (credentials) => async (dispatch) => { dispatch({ type: 'LOGIN_START' }) try { const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials) }) const user = await res.json() dispatch({ type: 'LOGIN_SUCCESS', payload: user }) } catch (err) { dispatch({ type: 'LOGIN_ERROR', payload: err.message }) } } ``` Тут: 1. **починаємо** завантаження (`LOGIN_START`), 2. **чекаємо** відповіді від сервера, 3. **завершуємо** дією успіху або помилки. --- ## 5. Що відбувається всередині Redux Без thunk: ```javascript dispatch({ type: 'INCREMENT' }) ↓ reducer(state, action) ↓ новий стан ``` З thunk: ```javascript dispatch(fetchUser(5)) ↓ redux-thunk бачить, що це функція ↓ викликає її -> fetch API -> dispatch звичайних actions ↓ reducer обробляє їх ↓ новий стан ``` --- ## 6. Головна різниця | Критерій | Звичайний Action | Thunk | |---|---|---| | Тип | Об'єкт | Функція | | Асинхронність | Ні | Так | | Куди йде | Одразу в reducer | В middleware (`redux-thunk`) | | Може викликати інші actions | Ні | Так | | Має доступ до `dispatch` / `getState` | Ні | Так | | Використовується для | Простих змін | Складної логіки (запити, ланцюжки, таймери) | --- ## 7. Візуально ```javascript Звичайний action: [dispatch] → [reducer] → [новий state] Thunk: [dispatch] → [redux-thunk middleware] → виконує функцію → [dispatch звичайних actions] → [reducer] ``` --- ## 8. Приклад у Redux Toolkit Redux Toolkit включає `redux-thunk` за замовчуванням, а його аналог - це `createAsyncThunk()`, який автоматизує роботу з thunks. ```javascript export const fetchUser = createAsyncThunk('user/fetch', async (id) => { const res = await fetch(`/api/users/${id}`) return await res.json() }) ``` Під капотом `createAsyncThunk` - це просто **автоматично створений thunk** з екшенами `pending`, `fulfilled`, `rejected`. --- ## Підсумок | Відмінність | Звичайний Action | Thunk | |---|---|---| | Тип | Об'єкт `{ type, payload }` | Функція `(dispatch, getState) => {}` | | Обробляється | Одразу в reducer | Middleware `redux-thunk` | | Асинхронність | Немає | Є | | Мета | Описати "що сталося" | Описати "що потрібно зробити" | | Може dispatch'ити інші actions | Ні | Так | | Використовується для | Простих подій | Запитів, складної логіки | --- **Коротко:** > Звичайний action - це *повідомлення про подію*. > Thunk - це *функція-план дій*, яка може виконувати асинхронну роботу > і сама відправляти потрібні звичайні actions у потрібний момент.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.