什么是mapDispatchToProps?


357

我正在阅读Redux库的文档,其中包含以下示例:

除了读取状态之外,容器组件还可以调度动作。以类似的方式,您可以定义一个名为的函数mapDispatchToProps(),该函数接收dispatch()方法并返回要注入到演示组件中的回调道具。

这实际上是没有意义的。为什么现在mapDispatchToProps已经有需要mapStateToProps

他们还提供了以下方便的代码示例:

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

有人可以用外行的术语解释一下这个功能是什么以及为什么有用吗?

Answers:


577

我觉得没有一个答案明确了为什么mapDispatchToProps有用。

实际上,这只能在container-component模式的上下文中得到回答,我首先阅读以下内容可以最好地理解该模式:容器组件,然后与React结合使用

简而言之,您components应该只关心显示内容。他们应该从中获取信息唯一地方是他们的道具

与“显示内容”(组件)分开的是:

  • 您如何展示这些东西,
  • 以及您如何处理事件。

那是containers为了什么。

因此,模式中的“精心设计” component如下所示:

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

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

查看此组件如何从props(来自redux存储,通过mapStateToProps)获取它显示的信息,以及如何从props:获取其action函数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,它知道Redux的调度和存储以及州和......东西。

component模式中的in进行FancyAlerter渲染不需要了解任何东西:它onClick通过其props 获取其在按钮处调用的方法。

还有... mapDispatchToProps是redux提供的有用手段,它可以使容器轻松地将该函数传递给其props上的包装组件。

所有这些看起来都非常像docs中的todo示例,还有另一个答案,但是我试图根据模式来强调它为什么

(请注意:您不能mapStateToProps出于mapDispatchToProps无法访问dispatch内部的基本原因而将其用于同一目的mapStateToProp。因此,您不能使用mapStateToProps来为包装的组件提供使用的方法dispatch

我不知道他们为什么选择将其分为两个映射功能-IE可以mapToProps(state, dispatch, props) 同时使用这两个功能可能更简单!


1 请注意,我故意将容器明确命名为FancyButtonContainer,以强调它是一个“事物”- 容器的“物”的身份(并因此存在!)有时会在速记中丢失

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

大多数示例中显示的语法


5
我仍然想知道:直接从组件内部调用store.dispatch无法处理所需的功能吗?
pixelpax

8
@ user2130130无。这是关于好的设计。如果您将组件与store.dispatch耦合,那么当您决定排除redux或要在不基于redxu的某个地方(或我现在无法想到的其他地方)使用redux时,您将陷入困境。很多变化。您的问题通常归结为“我们为什么要打扰'良好的设计规范'-无论您编写什么代码,都得到相同的功能”。提供了mapDispatchToProps,因此您可以编写设计良好,分离明确的组件。
GreenAsJade

4
我真正不明白的是:ALERT_ACTION动作函数还是type从动作函数返回的那个?:/莫名其妙
Jamie Hutber

1
@JamieHutber严格来说,ALERT_ACTION与这个问题无关。这是一个有效的调度参数,在我的代码中,它来自“操作生成器”,该操作器返回一个调度使用的对象,如redux.js.org/docs/api/Store.html#dispatch中所述。这里的要点是,如何在容器中描述如何调用dispatch,并将其传递给组件props。该组件只能从其道具获得功能,而无处可去。在此模式下执行此操作的“错误”方法是将调度传递给组件,并在组件中进行相同的调用。
GreenAsJade

1
如果您有多个动作创建者需要作为道具传递给子组件,则另一种方法是将它们与bindActionCreators一起包装在mapDispatchToProps内部(请参见redux.js.org/docs/api/bindActionCreators.html);另一种替代方法是简单地将动作创建者的对象提供给connect(),例如connect(mapStateToProps,{actioncreators}),react-redux将为您将它们包装在dispatch()中。
戴夫

81

基本上是简写。因此,不必写:

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

您将使用示例代码中所示的mapDispatchToProps,然后在其他地方编写:

this.props.onTodoClick(id);

或更可能是这种情况,您可以将其用作事件处理程序:

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

丹·阿布拉莫夫(Dan Abramov)在此提供了一个有用的视频:https : //egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist


谢谢。我也想知道,调度如何首先添加到道具中?
窃窃私语者代码

14
如果您不提供自己的mapDispatch功能,则Redux将使用默认值。该默认mapDispatch函数只是采用dispatch函数引用,并以的形式提供给您this.props.dispatch
–markerikson

7
调度方法传递下降的提供者组件
迭戈哈兹

55

mapStateToProps()是一个实用程序,可以帮助您的组件获取更新的状态(由其他一些组件更新),
mapDispatchToProps()是一个实用程序,可以帮助您的组件触发一个动作事件(调度动作可能会导致应用程序状态更改)


23

mapStateToPropsmapDispatchToProps并且connect来自react-redux库提供了一种方便的方式来访问您的商店statedispatch商店功能。因此,基本上connect是一个更高阶的组件,如果您认为合适的话,也可以将其视为包装器。因此,每次state更改mapStateToProps时,新组件都会调用它state,随后在props更新组件时,它将运行render函数以在浏览器中渲染组件。mapDispatchToProps还将键值存储在props组件的上,通常它们采用函数形式。通过这种方式,您可以触发state来自组件onClickonChange事件的更改。

从文档:

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无状态函数高阶组件


那么派发基本上就像事件一样?
Whisperer码

2
它可能与事件有关,调度只是一个功能,并且是更改应用程序状态的唯一方法。mapStateToProps是将商店的分派功能公开给React Component的一种方法。还要注意,connect并不是redux的一部分,实际上它只是一个实用程序,样板化的简化库称为react-redux可以与react和redux一起使用。 如果将存储从root react组件传递给子代,则无需使用react-redux即可获得相同的结果。
弗拉德·菲利蒙(Flad Filimon)2016年

3

mapStateToProps接收state和,props并允许您从状态中提取道具以传递给组件。

mapDispatchToProps接收dispatchprops,用于绑定操作创建者以进行分派,因此当您执行结果函数时,将分派操作。

我发现这仅使您不必dispatch(actionCreator())在组件中执行操作,从而使其更易于阅读。

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


谢谢,但是该dispatch方法的价值是什么?它从何而来?
窃窃私语的代码

哦。调度基本上使动作开始Redux / flux单向流。其他答案似乎比这更好地回答了您的问题。
哈里·莫雷诺

另外,调度方法来自其<Provider/>自身提供的增强功能。它执行自己的高级组件魔术,以确保在其子组件中可以进行分派。
里卡多·玛加良斯

3

现在假设有一个针对redux的操作:

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's call here
        dispatch(addTodo())
      }
    }
}

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

就像函数名称所说的那样mapDispatchToProps(),将dispatch动作映射到props(我们组件的props)

因此,道具onTodoClickmapDispatchToProps功能的关键,代表功能进一步派遣行动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())
      }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.