Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Возврат данных в action: паттерны и подходы
Вопрос о том, должна ли функция action (dispatch) возвращать данные, зависит от контекста использования и архитектурных решений. Это важный аспект проектирования state management.
Контекст и история
В различных state management решениях (Redux, Vuex, NgRx) подход к возврату значений из actions различается:
// Redux - action creators возвращают action object
function addTodo(text) {
return {
type: 'ADD_TODO',
payload: { text }
};
}
// Redux-Thunk - можем возвращать Promise
const addTodoAsync = (text) => async (dispatch) => {
const result = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify({ text })
});
const data = await result.json();
dispatch({ type: 'TODO_ADDED', payload: data });
return data;
};
Различные подходы
1. Action не возвращает ничего
Классический Redux подход - action creator только изменяет состояние, не возвращая данные.
const store = createStore(reducer);
// Action не возвращает результат
dispatch(addTodo('Купить молоко'));
// undefined
// Данные получаем из store
const todos = store.getState().todos;
Преимущества: простота и предсказуемость. Недостатки: нужно делать отдельный запрос к store для получения результата.
2. Action возвращает Promise
Современный подход - action возвращает Promise с результатом.
const createTodo = (title) => async (dispatch) => {
dispatch({ type: 'LOADING', payload: true });
try {
const response = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify({ title })
});
const todo = await response.json();
dispatch({
type: 'TODO_CREATED',
payload: todo
});
return todo;
} catch (error) {
dispatch({ type: 'ERROR', payload: error });
throw error;
}
};
// Использование
const newTodo = await dispatch(createTodo('Новая задача'));
console.log(newTodo);
Преимущества: удобно получить результат. Недостатки: может привести к дублированию данных.
Практические примеры
Пример 1: React + Redux
// actions.ts
export const fetchUser = (userId) => async (dispatch) => {
dispatch({ type: 'LOADING' });
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
dispatch({ type: 'USER_LOADED', payload: user });
return user;
} catch (error) {
dispatch({ type: 'ERROR', payload: error.message });
throw error;
}
};
// component.tsx
function UserProfile({ userId }) {
const dispatch = useDispatch();
const user = useSelector(state => state.user);
useEffect(() => {
dispatch(fetchUser(userId)).then(() => {
// данные уже в state
});
}, [userId, dispatch]);
return <div>{user?.name}</div>;
}
Пример 2: Vue + Vuex
const actions = {
async createPost({ commit }, content) {
const response = await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify({ content })
});
const post = await response.json();
commit('ADD_POST', post);
return post;
}
};
// component.vue
const handleCreatePost = async () => {
try {
const post = await this.createAction('createPost', this.content);
this.showNotification(`Пост создан: ${post.id}`);
} catch (error) {
this.showError(error.message);
}
};
Пример 3: Angular + NgRx
export const loadUser = createAction(
'[User] Load User',
props<{ userId: string }>()
);
export class UserEffects {
loadUser$ = createEffect(() =>
this.actions$.pipe(
ofType(loadUser),
switchMap(({ userId }) =>
this.userService.getUser(userId).pipe(
map(user => loadUserSuccess({ user }))
)
)
)
);
}
Рекомендации
Возвращать данные когда:
- Асинхронные операции (fetch, save)
- Нужен результат для выполнения следующего действия
- Есть побочные эффекты (navigation, уведомления)
Не возвращать когда:
- Простые изменения state (toggle флага)
- Операции только для обновления UI
Современный подход: React Query
function UserProfile({ userId }) {
const { data: user, isLoading, error } = useQuery(
['user', userId],
() => fetch(`/api/users/${userId}`).then(r => r.json())
);
const { mutateAsync: createTodo } = useMutation(
(title) => fetch('/api/todos', {
method: 'POST',
body: JSON.stringify({ title })
}).then(r => r.json()),
{
onSuccess: (newTodo) => {
console.log('Создана:', newTodo);
}
}
);
const handleSubmit = async () => {
const todo = await createTodo('Новая задача');
console.log('Результат:', todo);
};
}
Выводы
-
Возвращать Promise рекомендуется для асинхронных операций в современных приложениях
-
Не возвращать для простых синхронных изменений state
-
Использовать React Query или SWR для управления данными с сервера
-
Action должна возвращать результат, если он нужен для логики, но состояние всегда должно быть источником истины