Что такое mapDispatchToProps?

Я читал документацию по библиотеке Redux, и у нее есть такой пример:

В дополнение к чтению состояния компоненты контейнера могут отправлять действия. Аналогичным образом вы можете определить функцию с именем mapDispatchToProps(), которая получает метод dispatch() и возвращает реквизиты обратного вызова, которые вы хотите внедрить в компонент представления.

Это на самом деле не имеет смысла. Зачем вам нужен mapDispatchToProps, когда у вас уже есть mapStateToProps?

Они также предоставляют этот удобный пример кода:

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

Может ли кто-нибудь объяснить в терминах непрофессионала, что это за функция и почему она полезна?

Ответ 1

Я чувствую, что ни один из ответов не выяснил, почему mapDispatchToProps полезен.

На этот вопрос действительно можно ответить только в контексте шаблона container-component, который я нашел наиболее понятным при первом прочтении:Контейнерные компоненты, а затем Использование с React.

Короче говоря, ваш components должен заниматься только отображением вещей. Единственное место, откуда они должны получать информацию, это их реквизит.

Отдельно от "отображения материала" (компонентов) есть:

  • как вы получаете материал для отображения,
  • и как вы обрабатываете события.

Вот для чего containers.

Поэтому "хорошо спроектированный" component в шаблоне выглядит следующим образом:

class FancyAlerter extends Component {
    sendAlert = () => {
        this.props.sendTheAlert()
    }

    render() {
        <div>
          <h1>Today Fancy Alert is {this.props.fancyInfo}</h1>
          <Button onClick={sendAlert}/>
        </div>
     }
}

Посмотрите, как этот компонент получает информацию, которую он отображает из реквизитов (которая поступила из хранилища редуксов через mapStateToProps), и он также получает свою функцию действия из своих реквизитов: sendTheAlert().

То, где mapDispatchToProps входит: в соответствующем container

// FancyButtonContainer.js

function mapDispatchToProps(dispatch) {
    return({
        sendTheAlert: () => {dispatch(ALERT_ACTION)}
    })
}

function mapStateToProps(state) {
    return({fancyInfo: "Fancy this:" + state.currentFunnyString})
}

export const FancyButtonContainer = connect(
    mapStateToProps, mapDispatchToProps)(
    FancyAlerter
)

Интересно, видите ли вы, что теперь это container 1, который знает о редуксе, диспетчеризации, хранении, состоянии и... вещах.

component в паттерне, FancyAlerter, который выполняет рендеринг, не нужно знать о какой-либо из этих вещей: он получает свой метод для вызова в onClick кнопки через свои реквизиты.

И... mapDispatchToProps был полезным средством, которое предоставляет redux, чтобы позволить контейнеру легко передавать эту функцию в обернутый компонент на его подпорках.

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

(Примечание: вы не можете использовать mapStateToProps для той же цели, что и mapDispatchToProps, по той основной причине, что у вас нет доступа к dispatch внутри mapStateToProp. Поэтому вы не можете использовать mapStateToProps для обернутый компонент метод, который использует dispatch.

Я не знаю, почему они решили разбить его на две функции отображения - возможно, было бы лучше иметь mapToProps(state, dispatch, props) IE одну функцию для выполнения обеих!


1 Обратите внимание, что я намеренно явно назвал контейнер FancyButtonContainer, чтобы подчеркнуть, что это "вещь" - идентичность (и, следовательно, существование!) Контейнера как "вещи" иногда теряется в стенографии

export default connect(...) ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

синтаксис, который показан в большинстве примеров

Ответ 2

Это в основном стенография. Поэтому вместо того, чтобы писать:

this.props.dispatch(toggleTodo(id));

Вы должны использовать mapDispatchToProps, как показано в вашем примере кода, а затем в другом месте:

this.props.onTodoClick(id);

или, более вероятно, в этом случае вы должны иметь это как обработчик события:

<MyComponent onClick={this.props.onTodoClick} />

Здесь полезное видео Дэн Абрамов: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist

Ответ 3

mapStateToProps() - это утилита, которая помогает вашему компоненту получить обновленное состояние (которое обновляется некоторыми другими компонентами),
mapDispatchToProps() - это утилита, которая поможет вашему компоненту mapDispatchToProps() событие действия (диспетчерское действие, которое может вызвать изменение состояния приложения)

Ответ 4

mapStateToProps, mapDispatchToProps и connect из библиотеки react-redux предоставляет удобный способ доступа к вашему state и функции dispatch вашего магазина. Таким образом, по сути, соединение - это компонент высшего порядка, вы также можете подумать, что это обертка, если это имеет смысл для вас. Таким образом, каждый раз, когда ваше state изменяется, mapStateToProps будет вызываться с вашим новым state и впоследствии, когда вы обновляете props компонент запускает функцию рендеринга для отображения вашего компонента в браузере. mapDispatchToProps также хранит значения ключей на props вашего компонента, обычно они принимают форму функции. Таким образом, вы можете вызвать state изменения от компонента onClick, onChange событий.

Из документов:

const TodoListComponent = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

const TodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList) 

Также убедитесь, что вы знакомы с функциями React без сохранения состояния и компонентами высшего порядка.

Ответ 5

mapStateToProps получает state и props и позволяет извлекать реквизиты из состояния для передачи компоненту.

mapDispatchToProps получает dispatch и props и предназначена для того, чтобы связать создателей действий с диспетчеризацией, чтобы при выполнении результирующей функции действие отправлялось.

Я считаю, что это только избавляет вас от необходимости выполнять dispatch(actionCreator()) внутри вашего компонента, что делает его немного легче для чтения.

https://github.com/reactjs/react-redux/blob/master/docs/api.md#arguments

Ответ 6

Теперь предположим, что для редукса есть действие:

export function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

Когда вы импортируете его,

import {addTodo} from './actions';

class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.onTodoClick(); // This prop acts as key to callback prop for mapDispatchToProps
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

const mapDispatchToProps = dispatch => {
    return {
      onTodoClick: () => { // handles onTodoClick prop call here
        dispatch(addTodo())
      }
    }
}

export default connect(
    null,
    mapDispatchToProps
)(Greeting);

Как следует из названия функции mapDispatchToProps(), сопоставьте действие dispatch с реквизитами (реквизиты нашего компонента)

Поэтому prop onTodoClick является ключом к функции mapDispatchToProps которая делегирует дальнейшее действие для отправки действия addTodo.

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

import {addTodo} from './actions';
class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.addTodo();
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

export default connect(
    null,
    {addTodo}
)(Greeting);

Что именно означает

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}