什么是 mapDispatchToProps?

IT技术 reactjs redux react-redux mapdispatchtoprops
2021-03-31 23:54:18

我正在阅读 Redux 库的文档,它有这个例子:

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

这实际上没有任何意义。既然mapDispatchToProps已经有了,为什么还需要mapStateToProps

他们还提供了这个方便的代码示例:

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

这个函数是什么,为什么有用?

6个回答

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

这实际上只能在container-component模式的上下文中得到回答,我发现通过第一次阅读可以最好地理解它:Container Components then Usage with React

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

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

  • 你如何让这些东西显示出来,
  • 以及您如何处理事件。

那是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 store 通过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、dispatch、store、state 和......东西。

component图案中,FancyAlerter,这并呈现并不需要了解任何东西:它得到它的方法调用的onClick按钮,通过它的props。

并且 ...mapDispatchToProps是 redux 提供的有用方法,可以让容器轻松地将该函数传递到其 props 上的包装组件中。

所有这些看起来都非常像文档中的 todo 示例,还有这里的另一个答案,但我试图根据模式进行投射以强调原因

(注意:您不能mapStateToProps出于与mapDispatchToProps您无权访问dispatchinside的基本原因相同的目的而使用mapStateToProp。因此,您不能使用mapStateToProps为包装的组件提供使用dispatch.

我不知道他们为什么选择将它分解为两个映射函数——让mapToProps(state, dispatch, props) IE 一个函数同时执行这两个函数可能会更整洁


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

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

大多数示例中显示的语法

如果您有多个动作创建者需要作为道具传递给子组件,一种替代方法是在 mapDispatchToProps 中使用 bindActionCreators 将它们包装起来(请参阅redux.js.org/docs/api/bindActionCreators.html);另一种选择是简单地为 connect() 提供一个动作创建者的对象,例如,connect(mapStateToProps, {actioncreators}),react-redux 将为您用 dispatch() 包装它们。
2021-05-31 23:54:18
我仍然想知道:无法通过从组件内直接调用 store.dispatch 来处理所需的功能怎么办?
2021-06-04 23:54:18
@ user2130130 无。这是关于好的设计。如果你将你的组件与 store.dispatch 结合起来,那么当你决定将 redux 排除在外,或者想在某个不是基于 redxu 的地方(或者我现在想不到的其他东西)使用它时,你就会陷入困境很多变化。您的问题概括为“为什么我们要为‘良好的设计实践’而烦恼——无论您如何编码,您都可以获得相同的功能”。提供了 mapDispatchToProps 以便您可以编写设计良好、完全解耦的组件。
2021-06-11 23:54:18
@JamieHutber 严格来说,ALERT_ACTION 与这个问题无关。它是 dispatch 的有效参数,并且碰巧在我的代码中它来自“动作构建器”,它返回 dispatch 使用的对象,如redux.js.org/docs/api/Store.html#dispatch . 这里的重点是如何调用dispatch是在容器中描述的,并在组件props上传入。组件只能从它的 props 中获取函数,其他地方都没有。在此模式中执行此操作的“错误”方法是将 dispatch 传递给组件并在组件中进行相同的调用。
2021-06-14 23:54:18
我在这里真正不明白的是:ALERT_ACTION是动作函数还是type从动作函数返回的?:/ 太难了
2021-06-20 23:54:18

它基本上是一个速记。所以不必写:

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

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

this.props.onTodoClick(id);

或者更有可能在这种情况下,您将其作为事件处理程序:

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

Dan Abramov 在这里有一个有用的视频: Redux: Generating Containers with connect() from React Redux (VisibleTodoList)

谢谢你。我也想知道,首先如何将 dispatch 添加到 props 中?
2021-06-07 23:54:18
dispatch 方法由Provider 组件传递
2021-06-08 23:54:18
如果您不提供自己的mapDispatch函数,Redux 将使用默认值。该默认mapDispatch函数仅接受dispatch函数引用,并将其作为this.props.dispatch.
2021-06-15 23:54:18

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

mapStateToProps,mapDispatchToPropsconnectfrom react-reduxlibrary 提供了一种方便的方式来访问您的商店statedispatch功能。所以基本上 connect 是一个高阶组件,如果这对你有意义,你也可以认为它是一个包装器。因此,每次您state更改时,mapStateToProps都会使用您的新组件调用,state随后在您props更新组件时将运行渲染函数以在浏览器中呈现您的组件。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 无状态函数高阶组件

它可能与事件有关,调度只是一个函数,也是改变应用程序状态的唯一方法mapStateToProps是一种将你的store 的dispatch函数暴露给 React 组件的方法。另请注意,connect 不是redux的一部分,实际上它只是一个实用程序和样板reduce 库,称为react-redux,用于处理react 和redux。 如果您将商店从根 react 组件传递给子组件,无需react-redux即可获得相同的结果
2021-05-27 23:54:18
所以调度基本上就像事件?
2021-06-18 23:54:18

现在假设 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)

所以 proponTodoClickmapDispatchToProps函数的关键,它进一步委托 dispatch action 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())
      }
    }
}