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

Как action попадет в store?

2.0 Middle🔥 201 комментариев
#Soft Skills и рабочие процессы

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

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

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

Как action попадет в store?

Общая архитектура (Flux паттерн)

Action — это объект, содержащий информацию о том, что произошло. Store — это хранилище состояния. Путь от action к store зависит от выбранной библиотеки.

Redux: Классический подход

В Redux есть четкий flow (Flux):

UI (dispatch) -> Action -> Reducer -> Store -> View Update

Пример:

// 1. Определяем action
const INCREMENT = 'INCREMENT';
const increment = (amount) => ({
  type: INCREMENT,
  payload: amount
});

// 2. Определяем reducer (чистая функция)
function counterReducer(state = 0, action) {
  switch (action.type) {
    case INCREMENT:
      return state + action.payload;
    default:
      return state;
  }
}

// 3. Создаем store
const store = createStore(counterReducer);

// 4. Dispatch action из компонента
function Counter() {
  const dispatch = useDispatch();
  const count = useSelector(state => state);
  
  return (
    <div>
      <p>{count}</p>
      {/* Action отправляется -> редьюсер -> новое состояние -> re-render */}
      <button onClick={() => dispatch(increment(1))}>+1</button>
    </div>
  );
}

Как это работает:

  1. dispatch(increment(1)) отправляет action { type: 'INCREMENT', payload: 1 }
  2. Store пропускает action через reducer
  3. Reducer возвращает новое состояние
  4. Store обновляется и уведомляет подписчиков
  5. Компонент перерендерится с новым значением

Effector: Граф вычислений

В Effector нет редьюсеров, вместо этого используется событийная модель:

// 1. Создаем event (как action)
const incremented = createEvent('incremented');

// 2. Создаем store с изначальным значением
const $counter = createStore(0);

// 3. Связываем event с обновлением store
$counter.on(incremented, (state, amount) => state + amount);

// 4. В компоненте вызываем event
function Counter() {
  const counter = useUnit($counter);
  const handleClick = useUnit(incremented);
  
  return (
    <div>
      <p>{counter}</p>
      {/* Клик -> event -> обновление store -> re-render */}
      <button onClick={() => handleClick(1)}>+1</button>
    </div>
  );
}

Flow в Effector:

handleClick(1) -> incremented(1) -> $counter.on(...) -> обновление $counter -> подписчики

Zustand: Простой и минималистичный

import create from 'zustand';

// 1. Создаем store с actions
const useCounterStore = create((set) => ({
  count: 0,
  // Action — это метод в store
  increment: (amount) => set((state) => ({
    count: state.count + amount
  })),
  decrement: (amount) => set((state) => ({
    count: state.count - amount
  }))
}));

// 2. В компоненте вызываем action
function Counter() {
  const { count, increment } = useCounterStore();
  
  return (
    <div>
      <p>{count}</p>
      {/* increment -> set -> обновление store -> re-render */}
      <button onClick={() => increment(1)}>+1</button>
    </div>
  );
}

MobX: Reactive Programming

class CounterStore {
  count = 0;
  
  // Action
  increment(amount) {
    this.count += amount; // Прямое изменение state
  }
}

const counterStore = new CounterStore();

function Counter() {
  // MobX автоматически отслеживает изменения
  return (
    <div>
      <p>{counterStore.count}</p>
      {/* Action -> изменение свойства -> re-render через mobx-react */}
      <button onClick={() => counterStore.increment(1)}>+1</button>
    </div>
  );
}

Реальный пример с асинхронностью (Redux Thunk)

// Action creator, который возвращает функцию
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'LOADING' });
  try {
    const user = await api.getUser(userId);
    // Второе action после успешной загрузки
    dispatch({ type: 'LOADED', payload: user });
  } catch (error) {
    dispatch({ type: 'ERROR', payload: error });
  }
};

// В компоненте
function UserProfile({ userId }) {
  const dispatch = useDispatch();
  const { user, loading, error } = useSelector(state => state.user);
  
  useEffect(() => {
    // dispatch отправляет thunk вместо простого action
    dispatch(fetchUser(userId));
  }, [userId, dispatch]);
  
  if (loading) return <Spinner />;
  if (error) return <Error msg={error} />;
  return <div>{user.name}</div>;
}

Диаграмма всех подходов

Redux:        dispatch(action) -> middleware -> reducer -> store
Effector:     event(data) -> .on() handlers -> store -> subscriptions  
Zustand:      action() -> set() -> store -> subscriptions
MobX:         mutate state -> reactivity -> re-render
Context:      setState() -> Provider value -> useContext() -> re-render

Ключевые принципы

  1. Action — это описание того, что произошло
  2. Reducer/Handler — определяет, как обновить state
  3. Store — хранит текущее состояние
  4. Subscription — компоненты подписаны на изменения
  5. Re-render — когда state изменяется, компонент перерендерится

Заключение

Основной pattern остается один и тот же во всех библиотеках:

Action -> (Reducer/Handler/Mutation) -> Store -> Component Update

Выбор инструмента зависит от сложности приложения и предпочтений команды. Redux подходит для больших приложений, Zustand для простых, Effector для сложной логики, MobX для реактивного стиля.

Как action попадет в store? | PrepBro