Редюсери та екстраредюсери в Redux: Як вони працюють і в чому різниця
Redux — це популярна бібліотека для управління станом у JavaScript-додатках, особливо в React. У центрі роботи Redux стоїть концепція редюсерів. Сьогодні ми розглянемо, що таке редюсери та екстраредюсери, як вони працюють і чим відрізняються, а також подивимося приклади використання.
Що таке редюсер?
Редюсер (reducer) — це функція, яка визначає, як змінюється стан додатка у відповідь на дії (actions). Редюсери є чистими функціями: вони приймають поточний стан та дію і повертають новий стан.
Приклад редюсера:
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
}
Ключові принципи редюсера:
- Чистота функції. Редюсер не має побічних ефектів.
- Незмінність стану. Стан не змінюється напряму, а створюється новий об’єкт із внесеними змінами.
- Детермінізм. Вхідні дані завжди дають однаковий результат.
Що таке екстраредюсер?
Екстраредюсер (extra reducer) — це концепція, яка використовується в Redux Toolkit, сучасному наборі інструментів для роботи з Redux. Екстраредюсери дозволяють обробляти дії, які визначені поза межами конкретного слайсу (slice).
Основна ідея екстраредюсерів
Звичайні редюсери пов’язані з діями, що створюються у межах одного слайсу. Екстраредюсери дозволяють обробляти:
- дії з інших слайсів,
- глобальні дії,
- асинхронні дії, створені за допомогою
createAsyncThunk
.
Приклад екстраредюсерів:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
// Асинхронна дія
export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
});
const userSlice = createSlice({
name: 'user',
initialState: { user: null, status: 'idle' },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.status = 'succeeded';
state.user = action.payload;
})
.addCase(fetchUser.rejected, (state) => {
state.status = 'failed';
});
},
});
export default userSlice.reducer;
У цьому прикладі екстраредюсери обробляють асинхронні дії, створені через createAsyncThunk
.
В чому різниця між редюсерами та екстраредюсерами?
Характеристика | Редюсер | Екстраредюсер |
---|---|---|
Зв’язок із діями | Обробляє дії, визначені в тому ж слайсі | Обробляє дії з інших слайсів чи глобальні |
Декларативність | Визначається через об’єкт у reducers |
Визначається через метод builder |
Основне використання | Простий стан і синхронні дії | Асинхронні дії чи складна логіка |
Коли використовувати екстраредюсери?
- Асинхронні операції. Якщо ваш додаток виконує асинхронні запити (наприклад, до API), екстраредюсери ідеально підходять для обробки різних станів (loading, succeeded, failed).
- Спільні дії. Коли кілька слайсів мають реагувати на одну й ту саму дію.
- Глобальні дії. Обробка подій, які не пов’язані з конкретним слайсом.
Як створити редюсер з екстраредюсерами
Крок 1: Створіть асинхронну дію (за потреби):
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
const response = await fetch('/api/posts');
return response.json();
});
Крок 2: Створіть слайс із екстраредюсерами:
const postsSlice = createSlice({
name: 'posts',
initialState: { items: [], status: 'idle' },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchPosts.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchPosts.fulfilled, (state, action) => {
state.status = 'succeeded';
state.items = action.payload;
})
.addCase(fetchPosts.rejected, (state) => {
state.status = 'failed';
});
},
});
export default postsSlice.reducer;
Висновок
Редюсери та екстраредюсери — це ключові інструменти для управління станом у Redux. Редюсери обробляють синхронні та локальні дії, тоді як екстраредюсери дозволяють розширювати логіку, обробляючи асинхронні або глобальні дії. Використовуючи ці підходи, можна створювати масштабовані та добре організовані додатки.