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é.
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)
Utilisation
const StartContainer = connect(null, mapDispatchToProps)(Start)
au lieu de
const StartContainer = connect(mapDispatchToProps)(Start)
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.
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);
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
.
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)
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);
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
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
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);
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);