¿Qué es mapDispatchToProps?

358

Estaba leyendo la documentación de la biblioteca Redux y tiene este ejemplo:

Además de leer el estado, los componentes del contenedor pueden enviar acciones. De manera similar, puede definir una función llamada mapDispatchToProps()que recibe el dispatch()método y devuelve los accesorios de devolución de llamada que desea inyectar en el componente de presentación.

Esto en realidad no tiene sentido. ¿Por qué lo necesitas mapDispatchToPropscuando ya lo tienes mapStateToProps?

También proporcionan esta práctica muestra de código:

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

¿Alguien puede explicar en términos simples qué es esta función y por qué es útil?

Code Whisperer
fuente

Respuestas:

578

Siento que ninguna de las respuestas ha cristalizado por qué mapDispatchToPropses útil.

Esto realmente solo se puede responder en el contexto del container-componentpatrón, que encontré mejor entendido por primera lectura: Componentes del contenedor y luego Uso con reacción .

En pocas palabras, componentsse supone que debes preocuparte solo por mostrar cosas. El único lugar del que se supone que deben obtener información es sus accesorios .

Separado de "mostrar cosas" (componentes) es:

  • cómo obtienes las cosas para mostrar,
  • y cómo manejas los eventos.

Para eso containersestán.

Por lo tanto, un "bien diseñado" componenten el patrón se ve así:

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

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

Ver cómo este componente se pone la información se muestra de puntales (que entró en la tienda a través de redux mapStateToProps) y también consigue su función de acción de sus puntales: sendTheAlert().

Ahí es donde mapDispatchToPropsentra: en el correspondientecontainer

// 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
)

Me pregunto si puedes ver, ahora que es el container 1 que sabe acerca de redux y despacho y tienda y estado y ... cosas.

El componenten el patrón, FancyAlerterque hace el renderizado, no necesita saber nada de eso: obtiene su método para llamar al onClickbotón, a través de sus accesorios.

Y ... mapDispatchToPropsfue el medio útil que proporciona redux para permitir que el contenedor pase fácilmente esa función al componente envuelto en sus puntales.

Todo esto se parece mucho al ejemplo de todo en los documentos, y otra respuesta aquí, pero he tratado de lanzarlo a la luz del patrón para enfatizar por qué .

(Nota: no puede usarlo mapStateToPropspara el mismo propósito que mapDispatchToPropspor la razón básica por la que no tiene acceso al dispatchinterior mapStateToProp. Por lo tanto, no puede usar mapStateToPropspara darle al componente empaquetado un método que use dispatch.

No sé por qué eligieron dividirlo en dos funciones de mapeo: ¡podría haber sido más ordenado tener mapToProps(state, dispatch, props) IE una función para hacer ambas cosas!


1 Tenga en cuenta que deliberadamente denominé explícitamente el contenedor FancyButtonContainer, para resaltar que es una "cosa": la identidad (y, por lo tanto, la existencia) del contenedor como "una cosa" a veces se pierde en la taquigrafía

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

sintaxis que se muestra en la mayoría de los ejemplos

GreenAsJade
fuente
55
Todavía me gustaría saber: ¿Qué pasa con la funcionalidad requerida que no se puede manejar llamando directamente a store.dispatch desde un componente?
pixelpax
8
@ user2130130 Ninguno. Se trata de un buen diseño. Si acoplaste tu componente a store.dispatch, cuando decidas factorizar redux, o quieras usarlo en algún lugar que no esté basado en redxu (o alguna otra cosa que no pueda pensar ahora) estás atascado con un Muchos cambios. Su pregunta generaliza a "por qué nos molestamos con las 'buenas prácticas de diseño': obtiene la misma funcionalidad sin importar cómo la codifique". Se proporciona mapDispatchToProps para que pueda escribir componentes bien diseñados y desacoplados.
GreenAsJade
44
Lo que realmente no entiendo aquí es qué es: ¿ ALERT_ACTIONes esa la función de acción o la typeque se devuelve de la función de acción? : / tan desconcertado
Jamie Hutber
1
@JamieHutber Estrictamente, ALERT_ACTION no tiene nada que ver con esta pregunta. Es un argumento válido para despachar, y como sucede, en mi código proviene de un "generador de acciones", que devuelve un objeto que usa el despacho, como se describe redux.js.org/docs/api/Store.html#dispatch . El punto principal aquí es que la forma de llamar al despacho se describe en el contenedor y se pasa a los accesorios de los componentes. El componente solo obtiene funciones de sus accesorios, en ningún otro lugar. La forma "incorrecta" de hacerlo en este patrón sería pasar el despacho al componente y hacer la misma llamada en el componente.
GreenAsJade
1
Si tiene múltiples creadores de acciones que deben pasarse al componente secundario como accesorios, una alternativa es envolverlos con bindActionCreators dentro de mapDispatchToProps (consulte redux.js.org/docs/api/bindActionCreators.html ); otra alternativa es simplemente proporcionar un objeto de creadores de acción para conectar (), por ejemplo, conectar (mapStateToProps, {actioncreators}), react-redux los envolverá con dispatch () para usted.
Dave
81

Básicamente es una taquigrafía. Entonces, en lugar de tener que escribir:

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

Usaría mapDispatchToProps como se muestra en su código de ejemplo, y luego escribiría en otro lugar:

this.props.onTodoClick(id);

o más probablemente en este caso, lo tendrías como el controlador de eventos:

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

Hay un video útil de Dan Abramov sobre esto aquí: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist

hamstu
fuente
Gracias. También me pregunto, ¿cómo se agrega el despacho a los accesorios en primer lugar?
Code Whisperer
14
Si no proporciona su propia mapDispatchfunción, Redux utilizará un valor predeterminado. Esa mapDispatchfunción predeterminada simplemente toma la dispatchreferencia de función y se la da como this.props.dispatch.
markerikson
77
El método de envío es transmitido por el Componente Proveedor
Diego Haz
55

mapStateToProps()es una utilidad que ayuda a su componente a obtener un estado actualizado (que es actualizado por algunos otros componentes),
mapDispatchToProps()es una utilidad que ayudará a su componente a activar un evento de acción (acción de envío que puede causar un cambio en el estado de la aplicación)

Saisurya Kattamuri
fuente
23

mapStateToProps, mapDispatchToPropsY connectde la react-reduxbiblioteca proporciona una manera conveniente de acceder a su statee dispatchfunción de su tienda. Básicamente, connect es un componente de orden superior, también puede pensar como un contenedor si esto tiene sentido para usted. Por lo tanto, cada vez que statese modifique mapStateToProps, se llamará con su nuevo componente statey, a medida que propsactualice el componente, se ejecutará la función de representación para representar su componente en el navegador. mapDispatchToPropstambién almacena valores-clave en propssu componente, generalmente toman la forma de una función. De esta manera, puede desencadenar statecambios desde su componente onClick, onChangeeventos.

De documentos:

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) 

También asegúrese de estar familiarizado con React funciones sin estado y componentes de orden superior

Vlad Filimon
fuente
Entonces, ¿el despacho es básicamente un evento?
Code Whisperer
2
Podría estar relacionado con el evento, el envío es solo una función y la única forma de cambiar el estado de su aplicación . mapStateToProps es una forma de exponer el despacho función de de su tienda a React Component. También tenga en cuenta que connect no es parte de redux, de hecho, es solo una utilidad y una biblioteca reductora llamada react-redux para trabajar con react y redux. Puede lograr el mismo resultado sin react-redux si pasa su tienda del componente de reacción raíz a los niños.
Vlad Filimon
3

mapStateToPropsrecibe el statey propsy le permite extraer accesorios del estado para pasar al componente.

mapDispatchToPropsrecibe dispatchy propsestá destinado a que usted obligue a los creadores de acciones a despachar, de modo que cuando ejecuta la función resultante, la acción se despacha.

Creo que esto solo le evita tener que hacerlo dispatch(actionCreator())dentro de su componente, lo que lo hace un poco más fácil de leer.

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

Harry Moreno
fuente
Gracias, pero ¿cuál es el valor del dispatchmétodo? ¿De dónde viene?
Code Whisperer
Oh. El envío básicamente hace que la acción comience el flujo unidireccional redux / flux. Las otras respuestas parecen haber respondido a su pregunta mejor que esto.
Harry Moreno
Además, el método de envío proviene de la mejora proporcionada por el <Provider/>mismo. Realiza su propia magia de componentes de alto orden para garantizar que el envío esté disponible en sus componentes secundarios.
Ricardo Magalhães
3

Ahora suponga que hay una acción para redux como:

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

Cuando lo importas,

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);

Como dice el nombre de la función mapDispatchToProps(), mapadispatch acción a accesorios (los accesorios de nuestros componentes)

Por lo tanto, prop onTodoClickes una clave para la mapDispatchToPropsfunción que delega más allá para despachar acciones addTodo.

Además, si desea recortar el código y omitir la implementación manual, puede hacerlo,

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);

Que significa exactamente

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Conoce a Zaveri
fuente