Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое action в Redux
Action это обычный JavaScript объект, который описывает СОБЫТИЕ или НАМЕРЕНИЕ что-то изменить в состоянии приложения. Action это единственный способ отправить данные из компонента в Redux store.
Базовое определение Action
Action это объект с обязательным полем type:
// Простой action
const action = {
type: 'INCREMENT'
};
// Action с payload (данными)
const action = {
type: 'ADD_TODO',
payload: 'Купить молоко'
};
// Action с несколькими полями
const action = {
type: 'SET_USER',
payload: {
id: 1,
name: 'John',
email: 'john@example.com'
}
};
Ключевые свойства:
type(обязательно) - строка, описывающая что произошлоpayload(опционально) - данные для изменения состояния- Другие поля (опционально) - дополнительная информация
Action Creators - функции для создания Actions
Нормальная практика обернуть создание action в функцию:
// Простой action creator
const increment = () => ({
type: 'INCREMENT'
});
// Action creator с параметром
const addTodo = (text) => ({
type: 'ADD_TODO',
payload: text
});
// Action creator с объектом
const setUser = (userId, userData) => ({
type: 'SET_USER',
payload: {
userId,
...userData
}
});
// Использование
dispatch(increment()); // { type: 'INCREMENT' }
dispatch(addTodo('Купить молоко')); // { type: 'ADD_TODO', payload: 'Купить молоко' }
Workflow: Action -> Dispatch -> Reducer -> State
Полный цикл Redux:
// 1. Определяем action
const incrementAction = {
type: 'INCREMENT'
};
// 2. Отправляем action с dispatch()
store.dispatch(incrementAction);
// или через action creator
store.dispatch(increment());
// 3. Reducer обрабатывает action
function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 4. Store обновляется
// Компоненты, которые подписаны на store, перерисовываются
Пример: Todo App с Actions
// Action types - константы (лучше практика)
const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
// Action creators
const addTodo = (text) => ({
type: ADD_TODO,
payload: {
id: Date.now(),
text,
completed: false
}
});
const removeTodo = (id) => ({
type: REMOVE_TODO,
payload: id
});
const toggleTodo = (id) => ({
type: TOGGLE_TODO,
payload: id
});
// Reducer обрабатывает actions
function todosReducer(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [...state, action.payload];
case REMOVE_TODO:
return state.filter(todo => todo.id !== action.payload);
case TOGGLE_TODO:
return state.map(todo =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
);
default:
return state;
}
}
// В компоненте
import { useDispatch } from 'react-redux';
function TodoApp() {
const dispatch = useDispatch();
const [input, setInput] = useState('');
const handleAddTodo = () => {
dispatch(addTodo(input)); // Отправляем action
setInput('');
};
return (
<div>
<input value={input} onChange={e => setInput(e.target.value)} />
<button onClick={handleAddTodo}>Add Todo</button>
</div>
);
}
Правила написания Actions
1. Actions должны быть синхронными (обычно)
// ❌ НЕПРАВИЛЬНО - асинхронность в action
const fetchUser = (id) => {
return fetch(`/api/user/${id}`)
.then(res => res.json());
};
// ✅ ПРАВИЛЬНО - асинхронность в async thunk (middleware)
import { createAsyncThunk } from '@reduxjs/toolkit';
const fetchUser = createAsyncThunk(
'user/fetchUser',
async (id) => {
const response = await fetch(`/api/user/${id}`);
return response.json();
}
);
2. Actions должны быть serializable (легко передавать)
// ❌ НЕПРАВИЛЬНО - функции нельзя сериализировать
const action = {
type: 'SET_HANDLER',
payload: () => console.log('clicked')
};
// ✅ ПРАВИЛЬНО - только данные
const action = {
type: 'SET_CALLBACK_ID',
payload: 'onClickHandler'
};
3. Избегай мутаций
// ❌ НЕПРАВИЛЬНО - изменяет исходный объект
const updateUser = (user) => ({
type: 'UPDATE_USER',
payload: user // Если потом изменить user, изменится и в action
});
// ✅ ПРАВИЛЬНО - копируем данные
const updateUser = (user) => ({
type: 'UPDATE_USER',
payload: { ...user } // Новый объект
});
FSA - Flux Standard Action (стандарт)
Unofficial стандарт для структуры actions:
const action = {
type: 'ADD_TODO',
payload: { text: 'Купить молоко' },
meta: { timestamp: Date.now() },
error: false
};
// Для ошибок
const errorAction = {
type: 'FETCH_USER_FAILED',
payload: new Error('Network error'),
meta: { userId: 1 },
error: true
};
Redux Toolkit - современный подход
Redux Toolkit упрощает создание actions и reducers:
import { createSlice } from '@reduxjs/toolkit';
const todoSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addTodo: (state, action) => {
state.push({
id: Date.now(),
text: action.payload,
completed: false
});
},
removeTodo: (state, action) => {
return state.filter(todo => todo.id !== action.payload);
},
toggleTodo: (state, action) => {
const todo = state.find(t => t.id === action.payload);
if (todo) {
todo.completed = !todo.completed;
}
}
}
});
// Автоматически генерируются action creators
export const { addTodo, removeTodo, toggleTodo } = todoSlice.actions;
// В компоненте
dispatch(addTodo('Купить молоко')); // Автоматически создает { type: 'todos/addTodo', payload: '...' }
Асинхронные Actions - Async Thunk
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// Thunk - функция, которая возвращает функцию
const fetchUsers = createAsyncThunk(
'users/fetchUsers',
async (_, { rejectWithValue }) => {
try {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Failed to fetch');
return await response.json();
} catch (error) {
return rejectWithValue(error.message);
}
}
);
const usersSlice = createSlice({
name: 'users',
initialState: { data: [], loading: false, error: null },
extraReducers: (builder) => {
builder
.addCase(fetchUsers.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchUsers.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = false;
})
.addCase(fetchUsers.rejected, (state, action) => {
state.error = action.payload;
state.loading = false;
});
}
});
// В компоненте
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchUsers()); // Отправляем async action
}, [dispatch]);
Итого
Action это основной строительный блок Redux:
- Описывает что произошло в приложении
- Отправляется через dispatch()
- Обрабатывается reducer-ом
- Обновляет состояние (state)
- Компоненты перерисовываются с новыми данными
Хороший action должен быть ясным, предсказуемым и содержать ровно столько информации, сколько нужно reducer-у для обновления состояния.