Что такое mapStateToProps и mapDispatchToProps?react-32

mapStateToProps и mapDispatchToProps — это функции, используемые в классическом подходе Redux для подключения React-компонентов к хранилищу (store) через функцию connect(). Хотя современный подход с хуками (useSelector и useDispatch) более предпочтителен, понимание этих концепций важно для работы с legacy-кодом.

1. mapStateToProps

Назначение: Выбирает необходимые части состояния из Redux-хранилища и передает их в компонент как пропсы.

Особенности:

  • Вызывается при каждом изменении состояния хранилища
  • Должна быть чистой функцией
  • Первый аргумент — текущее состояние (state), второй — собственные пропсы компонента (ownProps)
const mapStateToProps = (state, ownProps) => {
  return {
    // Выбираем нужные данные из store
    counter: state.counter,
    // Можем использовать ownProps для вычислений
    doubleCounter: state.counter * 2,
    // Фильтрация по пропсу компонента
    todo: state.todos.find(todo => todo.id === ownProps.todoId)
  };
};

2. mapDispatchToProps

Назначение: Предоставляет компоненту методы для отправки (dispatch) действий.

Три варианта использования:

1. Как функция (полный контроль над dispatch):

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    increment: () => dispatch({ type: 'INCREMENT' }),
    // С использованием action creators
    addTodo: (text) => dispatch(addTodoAction(text)),
    // С учетом ownProps
    reset: () => dispatch({ type: 'RESET', id: ownProps.id })
  };
};

2. Как объект (автоматическая обертка в dispatch):

const mapDispatchToProps = {
  increment: () => ({ type: 'INCREMENT' }),
  addTodo: addTodoAction // Автоматически будет dispatched
};

3. Пропустить (компонент получит только dispatch):

connect(mapStateToProps)(MyComponent);
// В компоненте: this.props.dispatch({ type: 'INCREMENT' })

Пример полного подключения

import { connect } from 'react-redux';
import { increment, addTodo } from '../actions';

const MyComponent = ({ counter, increment, addTodo }) => (
  <div>
    <span>{counter}</span>
    <button onClick={increment}>+</button>
    <button onClick={() => addTodo('Learn Redux')}>Add Todo</button>
  </div>
);

const mapStateToProps = state => ({
  counter: state.counter
});

const mapDispatchToProps = {
  increment,
  addTodo
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent);

Разница с современными хуками

Функция Аналог с хуками
mapStateToProps useSelector
mapDispatchToProps useDispatch + action creators

Пример с хуками:

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

function Counter() {
  const counter = useSelector(state => state.counter);
  const dispatch = useDispatch();

  return (
    <div>
      <span>{counter}</span>
      <button onClick={() => dispatch(increment())}>+</button>
    </div>
  );
}

Резюмируем

  1. mapStateToProps:

    • Селектор, преобразующий состояние Redux в пропсы компонента
    • Оптимизирует ререндеры через shallow comparison
    • Получает state и ownProps
  2. mapDispatchToProps:

    • Связывает action creators с методом dispatch
    • Может быть функцией или объектом
    • Позволяет инкапсулировать логику dispatch
  3. Основное отличие от хуков:

    • Более многословный синтаксис
    • Требует оборачивания компонента в connect()
    • Менее интуитивен для чтения
  4. Когда использовать:

    • В legacy-проектах
    • Для классовых компонентов
    • В HOC-компонентах

Современные React-приложения следует писать с использованием хуков useSelector и useDispatch, но понимание этих функций необходимо для поддержки старых кодовых баз.