Flux и Redux pattern

Однонаправленный поток данных для предсказуемого управления состоянием приложения.

Зачем нужно

  • Предсказуемость: состояние меняется только через actions
  • Отладка: time-travel debugging, логирование каждого изменения
  • Масштабируемость: единый store для всего приложения

Где используется

  • React-приложения (Redux, Redux Toolkit, Zustand), Vue (Vuex/Pinia)

Flux (концепция Facebook)

Action → Dispatcher → Store → View → Action
  • Action -- объект с типом события и данными
  • Dispatcher -- центральный хаб, рассылает actions в stores
  • Store -- хранит состояние и логику
  • View -- React-компонент, подписан на store

Redux (упрощённый Flux)

Action → Reducer → Store → Component

Три принципа

  1. Единый store -- одно дерево состояния
  2. Read-only state -- изменения только через dispatch(action)
  3. Pure reducers -- чистые функции (state, action) => newState

Пример (Redux Toolkit)

import { createSlice, configureStore } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => { state.value += 1; },
    decrement: (state) => { state.value -= 1; },
    addBy: (state, action) => { state.value += action.payload; },
  },
});

export const { increment, decrement, addBy } = counterSlice.actions;

const store = configureStore({
  reducer: { counter: counterSlice.reducer },
});

// Использование
store.dispatch(increment);
console.log(store.getState.counter.value); // 1

В React-компоненте

import { useSelector, useDispatch } from 'react-redux';
import { increment } from './counterSlice';

function Counter() {
  const count = useSelector((s: RootState) => s.counter.value);
  const dispatch = useDispatch;
  return <button onClick={ => dispatch(increment)}>{count}</button>;
}

Когда НЕ нужен Redux

  • Маленькое приложение (хватит useState/useContext)
  • Серверное состояние (лучше React Query / SWR)

Связанные темы

Ресурсы