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

Во что пакетируется код в Redhub-подобных архитектурах

3.0 Senior🔥 131 комментариев
#Микросервисы и архитектура

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Упаковка кода в Redux-подобных архитектурах

В Redux-подобных архитектурах (включая собственно Redux, Vuex, MobX, NgRx и другие реализации паттерна Flux) код организуется вокруг нескольких ключевых концепций, которые "пакетируются" определенным образом для обеспечения предсказуемости состояния приложения и одностороннего потока данных.

Основные архитектурные единицы

1. Store (Хранилище)

Централизованное хранилище состояния всего приложения. В Redux это всегда один объект, содержащий все состояние.

// Пример создания store в Redux
import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

2. Actions (Действия)

Объекты, которые описывают, что должно произойти в приложении. Это единственный способ изменить состояние.

// Action types
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// Action creators
export const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { text, id: Date.now(), completed: false }
});

export const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: { id }
});

3. Reducers (Редюсеры)

Чистые функции, которые принимают предыдущее состояние и action, возвращая новое состояние.

// Reducer
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, action.payload];
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.payload.id 
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
};

4. Middleware (Промежуточное ПО)

Функции, которые обрабатывают actions до того, как они достигнут редюсера.

// Пример middleware для логирования
const loggerMiddleware = store => next => action => {
  console.log('Dispatching:', action);
  const result = next(action);
  console.log('Next state:', store.getState());
  return result;
};

Организация кода на практике

По типам функциональности (Classic Redux)

src/
├── actions/
│   ├── todoActions.js
│   └── userActions.js
├── reducers/
│   ├── todoReducer.js
│   ├── userReducer.js
│   └── rootReducer.js
├── store/
│   └── configureStore.js
└── constants/
    └── actionTypes.js

По предметным областям (Ducks/Redux Toolkit)

Современный подход, где связанные действия, редюсеры и типы группируются вместе:

// features/todos/todosSlice.js (Redux Toolkit)
import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      state.push(action.payload);
    },
    toggleTodo: (state, action) => {
      const todo = state.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    }
  }
});

export const { addTodo, toggleTodo } = todosSlice.actions;
export default todosSlice.reducer;

Ключевые принципы упаковки

  1. Единственный источник истины - Все состояние приложения хранится в одном store
  2. State доступен только для чтения - Изменять состояние можно только через actions
  3. Изменения через чистые функции - Редюсеры должны быть чистыми функциями без side effects
  4. Односторонний поток данных - Data flow: View → Action → Reducer → Store → View

Современные тенденции

В современных реализациях, особенно с Redux Toolkit, код упаковывается более компактно:

  • Slices - Автоматическая генерация actions и reducers
  • RTK Query - Встроенное решение для работы с API
  • EntityAdapter - Стандартизированная работа с нормализованными данными
// Modern Redux с RTK
import { configureStore, createSlice } from '@reduxjs/toolkit';

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

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

Такой подход к упаковке кода обеспечивает масштабируемость, тестируемость и поддерживаемость крупных приложений, при этом сохраняя предсказуемость работы с состоянием.