Что такое 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())
}
}
}