← Назад к вопросам

Возвращал ли данные в action

2.0 Middle🔥 251 комментариев
#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Возврат данных в 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);
  };
}

Выводы

  1. Возвращать Promise рекомендуется для асинхронных операций в современных приложениях

  2. Не возвращать для простых синхронных изменений state

  3. Использовать React Query или SWR для управления данными с сервера

  4. Action должна возвращать результат, если он нужен для логики, но состояние всегда должно быть источником истины

Возвращал ли данные в action | PrepBro