web-dev-qa-db-fra.com

'dispatch' n'est pas une fonction lorsque l'argument de mapToDispatchToProps () dans Redux

Je suis un débutant javascript/redux/react construisant une petite application avec redux, react-redux, & react. Pour une raison quelconque, lorsque j'utilise la fonction mapDispatchToProps en même temps que connect (reliure react-redux), je reçois une TypeError indiquant que la répartition n'est pas une fonction lorsque j'essaie d'exécuter l'accessoire résultant. Cependant, lorsque j'appelle dispatch comme accessoire (voir la fonction setAddr dans le code fourni), cela fonctionne. 

Je suis curieux de savoir pourquoi. Dans l'exemple d'application TODO de la redux docs, la méthode mapDispatchToProps est configurée de la même manière. Lorsque je console.log (dispatch) dans la fonction, il est indiqué que dispatch est de type objet. Je pourrais continuer à utiliser la répartition de cette façon, mais je me sentirais mieux de savoir pourquoi cela se produit avant de continuer plus loin avec redux. J'utilise webpack avec babel-loaders pour compiler.

Mon code:

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

À votre santé.

72
sully

Il vous manque juste le premier argument de connect, qui est la méthode mapStateToProps. Extrait de l'application todo Redux:

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)
100
Brandon

Utilisation 

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

au lieu de 

const StartContainer = connect(mapDispatchToProps)(Start)
17
Ann

Je l'ai résolu en échangeant les arguments, j'utilisais 

export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)

ce qui est faux. La mapStateToProps doit être le premier argument:

export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)

Cela semble évident maintenant, mais pourrait aider quelqu'un.

4
Amit Mittal

J'avais besoin d'un exemple en utilisant React.Component alors je le publie:

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
Amio.io

Problème

Voici quelques points à noter pour comprendre le comportement du composant connecté dans votre code:

L'art de connect Matters: connect(mapStateToProps, mapDispatchToProps)

React-Redux appelle connect avec le premier argument mapStateToProps et le deuxième argument mapDispatchToProps

Par conséquent, bien que vous ayez passé votre mapDispatchToProps, React-Redux le traite en fait comme mapState car il s’agit du premier argument. Vous obtenez toujours la fonction onSubmit injectée dans votre composant car le retour de mapState est fusionné dans les accessoires de votre composant. Mais ce n’est pas ainsi que mapDispatch est censé être injecté.

Vous pouvez utiliser mapDispatch sans définir mapState. Transmettez null à la place de mapState et votre composant ne sera pas soumis aux modifications de la boutique.

Le composant connecté reçoit dispatch par défaut, si aucune mapDispatch n'est fournie

De plus, votre composant reçoit dispatch car il a reçu null pour sa deuxième position pour mapDispatch. Si vous transmettez correctement mapDispatch, votre composant ne recevra pas dispatch.

Pratique courante

Les réponses ci-dessus expliquent pourquoi le composant s'est comporté de cette manière. Cependant, il est de pratique courante que vous passiez simplement à votre créateur d’action en utilisant le raccourci d’objet de mapStateToProps. Et appelez cela dans la variable onSubmit de votre composant, à savoir:

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)
2
wgao19

Parfois, cette erreur se produit également lorsque vous modifiez l’ordre de la fonction de composant en passant pour vous connecter.

Ordre incorrect:

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

Bon ordre:

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

Un piège dans lequel certains pourraient entrer est couvert par cette question mais n'est pas abordé dans les réponses car il est légèrement différent dans la structure du code mais renvoie exactement la même erreur.

Cette erreur se produit lorsque vous utilisez bindActionCreators sans transmettre la fonction dispatch

Code d'erreur

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)

Code fixe

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 fonction dispatch était manquante dans le code d'erreur

0
TheyDontHaveIT

Lorsque vous ne fournissez pas mapDispatchToProps en tant que second argument, procédez comme suit: 

export default connect(mapStateToProps)(Checkbox)

vous obtenez alors automatiquement l'envoi des accessoires du composant, vous pouvez donc simplement:

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

sans mapDispatchToProps

0
Serge Nikolaev

La fonction 'connect' de React-redux accepte deux arguments: premièrement, mapStateToProps et deuxièmement, vérification de mapDispatchToProps, sous ex.

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

Si nous ne voulons pas récupérer l'état de redux, nous définissons null à la place de mapStateToProps.

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

0
Sachin Metkari

j'utilise comme ceci .. il est facile à comprendre le premier argument est mapStateToProps et le second argument est mapDispatchToProps à la fin se connecter avec la fonction/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);
0
Abdul Moiz