'dispatch' non è una funzione quando l'argomento di mapToDispatchToProps () in Redux


124

Sono un principiante di javascript / redux / react che costruisce una piccola applicazione con redux, react-redux e react. Per qualche motivo, quando utilizzo la funzione mapDispatchToProps in tandem con connect (binding react-redux) ricevo un TypeError che indica che l'invio non è una funzione quando provo a eseguire il prop risultante. Tuttavia, quando chiamo dispatch come prop (vedi la funzione setAddr nel codice fornito) funziona.

Sono curioso di sapere perché questo è, nell'esempio app TODO nei documenti redux il metodo mapDispatchToProps è impostato allo stesso modo. Quando console.log (invio) all'interno della funzione si dice che l'invio è di tipo oggetto. Potrei continuare a usare il dispatch in questo modo, ma mi sentirei meglio sapendo perché questo sta accadendo prima di continuare ulteriormente con il redux. Sto usando webpack con babel-loader per compilare.

Il mio codice:

import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import { setAddresses } from '../actions.js';
import GeoCode from './geoCode.js';
import FlatButton from 'material-ui/lib/flat-button';

const Start = React.createClass({
    propTypes: {
        onSubmit: PropTypes.func.isRequired
    },

    setAddr: function(){
        this.props.dispatch(
            setAddresses({
                pickup: this.refs.pickup.state.address,
                dropoff: this.refs.dropoff.state.address
            })
        )   

    },

    render: function() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-6">
                        <GeoCode ref='pickup' />
                    </div>
                    <div className="col-xs-6">
                        <GeoCode ref='dropoff' />
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Does Not Work'
                            onClick={this.props.onSubmit({
                                pickup: this.refs.pickup.state.address,
                                dropoff: this.refs.dropoff.state.address
                            })} 
                            />
                    </div>
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Works'
                            onClick={this.setAddr} 
                            />
                    </div>
                </div>
            </div>
        );
    }
})

const mapDispatchToProps = (dispatch) => {
    return {
        onSubmit: (data) => {
            dispatch(setAddresses(data))
        }
    }
}

const StartContainer = connect(mapDispatchToProps)(Start)

export default StartContainer

Saluti.


Stavo riscontrando questo problema e questo mi ha aiutato a risolverlo
Alex W

Risposte:


249

Se vuoi usare mapDispatchToPropssenza un mapStateToPropssolo uso nullper il primo argomento.

export default connect(null, mapDispatchToProps)(Start)


4
Questo è quello che stavo cercando. Ora so se voglio solo inviare alcune azioni.
Imperatore Krauser

Questo è esattamente qualcosa che stavo cercando. Grazie per la soluzione perfetta. E se non dovessimo usare mapDispatchToProps in nessuno dei nostri componenti? È lo stesso modo in cui dobbiamo gestire quello scenario?
Arun Ramachandran

1
Se non è necessario mapDispatchToProps, non aggiungere questo argomento a connect:connect(mapStateToProps)(MyComponent)
inostia

107

Ti manca solo il primo argomento per connect, che è il mapStateToPropsmetodo. Estratto dall'app Redux todo:

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

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

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

3
è obbligatorio utilizzare questo metodo? Questo metodo cattura solo lo stato e se non abbiamo bisogno di questo metodo?
Muneem Habib

6
@MuneemHabib vedi la risposta di inostia su come non fornire questo metodo se non ne hai bisogno
Brandon

21

Uso

const StartContainer = connect(null, mapDispatchToProps)(Start) 

invece di

const StartContainer = connect(mapDispatchToProps)(Start)

6

L'ho risolto scambiando gli argomenti che stavo usando

export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)

che è sbagliato. La mapStateToPropsdeve essere il primo argomento:

export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)

Sembra ovvio ora, ma potrebbe aiutare qualcuno.


3

Avevo bisogno di un esempio utilizzando React.Componentquindi lo sto pubblicando:

import React from 'react';
import * as Redux from 'react-redux';

class NavigationHeader extends React.Component {

}

const mapStateToProps = function (store) {
    console.log(`mapStateToProps ${store}`);
    return {
        navigation: store.navigation
    };
};

export default Redux.connect(mapStateToProps)(NavigationHeader);

3

Problema

Ecco un paio di cose da notare per comprendere il comportamento del componente connesso nel tuo codice:

The Arity of connectMatters:connect(mapStateToProps, mapDispatchToProps)

React-Redux chiama connectcon il primo argomento mapStateToPropse il secondo argomento mapDispatchToProps.

Pertanto, sebbene tu abbia passato il tuo mapDispatchToProps, React-Redux in realtà lo considera come mapStatese fosse il primo argomento. Hai ancora la onSubmitfunzione iniettata nel tuo componente perché il ritorno di mapStateviene unito agli oggetti di scena del tuo componente. Ma non è così che mapDispatchdovrebbe essere iniettato.

Puoi usare mapDispatchsenza definire mapState. Passa al nullposto di mapStatee il tuo componente non sarà soggetto a modifiche in negozio.

Il componente connesso riceve dispatchper impostazione predefinita, quando non mapDispatchviene fornito

Inoltre, il tuo componente riceve dispatchperché ha ricevuto nullper la sua seconda posizione per mapDispatch. Se passi correttamente mapDispatch, il tuo componente non riceverà dispatch.

Pratica comune

Quanto sopra risponde perché il componente si è comportato in quel modo. Anche se è pratica comune passare semplicemente al tuo creatore di azioni usando mapStateToPropsl'abbreviazione dell'oggetto di. E chiamalo all'interno del tuo componente onSubmitCioè:

import { setAddresses } from '../actions.js'

const Start = (props) => {
  // ... omitted
  return <div>
    {/** omitted */}
    <FlatButton 
       label='Does Not Work'
       onClick={this.props.setAddresses({
         pickup: this.refs.pickup.state.address,
         dropoff: this.refs.dropoff.state.address
       })} 
    />
  </div>
};

const mapStateToProps = { setAddresses };
export default connect(null, mapDispatchToProps)(Start)

0

Quando non fornisci mapDispatchToPropscome secondo argomento, in questo modo:

export default connect(mapStateToProps)(Checkbox)

quindi ricevi automaticamente l'invio agli oggetti di scena del componente, quindi puoi semplicemente:

class SomeComp extends React.Component {
  constructor(props, context) {
    super(props, context);
  }
  componentDidMount() {
    this.props.dispatch(ACTION GOES HERE);
  }
....

senza alcun mapDispatchToProps


0

Sto usando in questo modo .. il suo primo argomento facile da capire è mapStateToProps e il secondo argomento è mapDispatchToProps alla fine si connette con la funzione / classe.

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

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

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

se non hai il primo argomento, passa semplicemente null / undefined e poi il secondo argomento ..
Abdul Moiz

0

A volte questo errore si verifica anche quando si modifica l'ordine della funzione componente durante il passaggio alla connessione.

Ordine errato:

export default connect(mapDispatchToProps, mapStateToProps)(TodoList);

Ordine corretto:

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

0

Una trappola in cui qualcuno potrebbe incappare è trattata da questa domanda ma non viene affrontata nelle risposte poiché è leggermente diversa nella struttura del codice ma restituisce esattamente lo stesso errore.

Questo errore si verifica quando si utilizza bindActionCreatorse non si passa la dispatchfunzione

Codice di errore

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    });
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

Codice fisso

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    }, dispatch);
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

La funzione dispatchmancava nel codice di errore


0

La funzione 'connect' di React-redux accetta due argomenti: il primo è mapStateToProps e il secondo è mapDispatchToProps, controlla sotto es.

export default connect(mapStateToProps, mapDispatchToProps)(Index); `

Se non vogliamo recuperare lo stato da redux, impostiamo null invece di mapStateToProps.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.