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

Зачем нужен Media запрос?

2.0 Middle🔥 201 комментариев
#HTML и CSS

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

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

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

Зачем Redux организовано на экшены, хранилища и редьюсеры

Это архитектурное разделение ответственности для управления состоянием. Redux следует принципам Flux и функционального программирования.

Redux архитектура

┌───────────────┐
│  React View   │
└───────┬───────┘
        │
        │ Dispatch Action
        v
┌───────────────┐
│    Actions    │ {type: 'USER_LOGIN', payload}
└───────┬───────┘
        │
        │ Process
        v
┌───────────────┐
│   Reducers    │ (state, action) => newState
└───────┬───────┘
        │
        │ Update
        v
┌───────────────┐
│    Store      │ {users: [], auth: {}}
└───────┬───────┘
        │
        │ Subscribe
        v
┌───────────────┐
│  Components   │ re-render
└───────────────┘

1. Actions (описывают ЧТО произошло)

// Action = объект с типом и данными
const loginAction = {
  type: 'USER_LOGIN',
  payload: { userId: 123, name: 'John' }
};

// Action Creator (функция для создания action)
const login = (userId, name) => ({
  type: 'USER_LOGIN',
  payload: { userId, name }
});

// Использование
dispatch(login(123, 'John'));

Зачем отдельно:

  • Четкая структура (всегда type + payload)
  • Легко логировать события
  • Можно отладить любое действие
  • Тестировать просто (чистые функции)

2. Reducers (описывают КАК изменить состояние)

// Reducer = чистая функция
// (state, action) => newState

const initialState = {
  user: null,
  isLoading: false,
  error: null
};

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'USER_LOGIN':
      return {
        ...state,
        user: action.payload,
        error: null
      };
    
    case 'USER_LOGOUT':
      return {
        ...state,
        user: null
      };
    
    default:
      return state;
  }
};

Зачем отдельно:

  • Чистые функции (без побочных эффектов)
  • Легко тестировать (input -> output)
  • Предсказуемо (один action -> один результат)
  • Легко отладить (каждый шаг видно)

3. Store (единое хранилище состояния)

import { createStore } from 'redux';

const store = createStore(authReducer);

// Получить состояние
console.log(store.getState());

// Подписаться на изменения
store.subscribe(() => {
  console.log('Состояние изменилось:', store.getState());
});

// Отправить action
store.dispatch(login(123, 'John'));

Зачем отдельно:

  • Единое место истины (одно состояние)
  • Все компоненты видят одно состояние
  • Нет дублирования данных
  • Легко синхронизировать

Полный цикл Redux

// 1. Action (что произошло)
const action = {
  type: 'INCREMENT_COUNTER',
  payload: 1
};

// 2. Reducer (как изменить)
const counterReducer = (state = 0, action) => {
  if (action.type === 'INCREMENT_COUNTER') {
    return state + action.payload;
  }
  return state;
};

// 3. Store (где хранится)
const store = createStore(counterReducer);

// 4. Dispatch (отправить action)
store.dispatch(action);

// 5. Новое состояние
console.log(store.getState()); // 1

Зачем разделение

Без Redux (ad-hoc管理)

// Состояние повсюду
let user = null;
let isLoading = false;
let error = null;

// Функции изменяют глобальное состояние
function login(userId) {
  isLoading = true;
  fetchUser(userId).then(data => {
    user = data;      // Изменение
    isLoading = false; // Изменение
  });
}

// Проблемы:
// - Не понятно, кто изменил состояние
// - Сложно отследить изменения
// - Сложно тестировать
// - Race conditions

С Redux (структурированно)

// Actions - ясно ЧТО произошло
const LOGIN_START = 'LOGIN_START';
const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
const LOGIN_FAILURE = 'LOGIN_FAILURE';

// Reducers - ясно КАК изменить
const authReducer = (state, action) => {
  switch (action.type) {
    case LOGIN_START:
      return {...state, isLoading: true};
    case LOGIN_SUCCESS:
      return {...state, user: action.payload, isLoading: false};
    case LOGIN_FAILURE:
      return {...state, error: action.payload, isLoading: false};
  }
};

// Thunk middleware для async
const login = (userId) => (dispatch) => {
  dispatch({type: LOGIN_START});
  fetchUser(userId)
    .then(data => dispatch({type: LOGIN_SUCCESS, payload: data}))
    .catch(err => dispatch({type: LOGIN_FAILURE, payload: err}));
};

// Преимущества:
// - Все изменения отслеживаемы
// - Легко отладить (DevTools)
// - Чистые функции (тестируемо)
// - Нет race conditions

Middleware (для async операций)

// Thunk для async действий
const thunk = store => next => action => {
  if (typeof action === 'function') {
    return action(store.dispatch, store.getState);
  }
  return next(action);
};

// Использование
const fetchUser = (id) => async (dispatch) => {
  dispatch({type: 'LOADING'});
  try {
    const data = await fetch(`/api/users/${id}`).then(r => r.json());
    dispatch({type: 'SUCCESS', payload: data});
  } catch (e) {
    dispatch({type: 'ERROR', payload: e});
  }
};

Несколько reducers (combineReducers)

const authReducer = (state = {}, action) => {...};
const counterReducer = (state = 0, action) => {...};
const postsReducer = (state = [], action) => {...};

const rootReducer = combineReducers({
  auth: authReducer,
  counter: counterReducer,
  posts: postsReducer
});

const store = createStore(rootReducer);

// State структура
store.getState(); // {auth: {}, counter: 0, posts: []}

Redux DevTools (отладка)

// Видишь все actions в порядке
// Можешь перемотать любое действие
// Видишь, как изменилось состояние
// Экспортировать/импортировать состояние

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

Когда Redux нужен

✓ Много компонентов с общим состоянием
✓ Нужна отладка (DevTools)
✓ Сложная логика изменения состояния
✓ Нужно сохранить историю действий
✓ Коллаборативная разработка

✗ Простое приложение (используй useState)
✗ Локальное состояние компонента

Альтернативы

// Context API (проще, но менее мощно)
const StoreContext = createContext();

// Zustand (проще Redux)
const useStore = create((set) => ({
  user: null,
  setUser: (u) => set({user: u})
}));

// MobX (реактивное, но сложнее)
class Store {
  @observable user = null;
}

Заключение

Redux разделен на:

  1. Actions - описывают ЧТО произошло
  2. Reducers - описывают КАК изменить состояние
  3. Store - единое хранилище истины

Это разделение дает:

  • Предсказуемость
  • Отслеживаемость
  • Тестируемость
  • Отладку

Оно следует функциональному программированию и функции чистых (pure functions).