Comment obtenir une distribution simple de this.props en utilisant Connect w / Redux?

107

J'ai un simple composant React que je connecte (mappant un simple tableau / état). Pour éviter de référencer le contexte du magasin, j'aimerais avoir un moyen d'obtenir une «répartition» directement à partir des accessoires. J'en ai vu d'autres utiliser cette approche mais je n'y ai pas accès pour une raison quelconque :)

Voici les versions de chaque dépendance npm que j'utilise actuellement

"react": "0.14.3",
"react-redux": "^4.0.0",
"react-router": "1.0.1",
"redux": "^3.0.4",
"redux-thunk": "^1.0.2"

Voici le composant avec la méthode de connexion

class Users extends React.Component {
    render() {
        const { people } = this.props;
        return (
            <div>
                <div>{this.props.children}</div>
                <button onClick={() => { this.props.dispatch({type: ActionTypes.ADD_USER, id: 4}); }}>Add User</button>
            </div>
        );
    }
};

function mapStateToProps(state) {
    return { people: state.people };
}

export default connect(mapStateToProps, {
    fetchUsers
})(Users);

Si vous avez besoin de voir le réducteur (rien d'excitant mais le voici)

const initialState = {
    people: []
};

export default function(state=initialState, action) {
    if (action.type === ActionTypes.ADD_USER) {
        let newPeople = state.people.concat([{id: action.id, name: 'wat'}]);
        return {people: newPeople};
    }
    return state;
};

Si vous avez besoin de voir comment mon routeur est configuré avec redux

const createStoreWithMiddleware = applyMiddleware(
      thunk
)(createStore);

const store = createStoreWithMiddleware(reducers);

var Route = (
  <Provider store={store}>
    <Router history={createBrowserHistory()}>
      {Routes}
    </Router>
  </Provider>
);

mettre à jour

ressemble à si j'omettais ma propre répartition dans la connexion (actuellement ci-dessus, je montre fetchUsers), j'obtiendrais une distribution gratuite (mais je ne sais pas si c'est ainsi qu'une configuration avec des actions asynchrones fonctionnerait habituellement). Les gens se mélangent-ils ou sont-ils tout ou rien?

[mapDispatchToProps]

Toran Billups
la source

Réponses:

280

Par défaut, mapDispatchToPropsc'est juste dispatch => ({ dispatch }).
Donc, si vous ne spécifiez pas le deuxième argument à connect(), vous serez dispatchinjecté comme accessoire dans votre composant.

Si vous passez une fonction personnalisée à mapDispatchToProps, vous pouvez faire n'importe quoi avec la fonction.
Quelques exemples:

// inject onClick
function mapDispatchToProps(dispatch) {
  return {
    onClick: () => dispatch(increment())
  };
}

// inject onClick *and* dispatch
function mapDispatchToProps(dispatch) {
  return {
    dispatch,
    onClick: () => dispatch(increment())
  };
}

Pour vous épargner un peu de frappe, Redux vous bindActionCreators()permet d'activer ceci:

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return {
    onPlusClick: () => dispatch(increment()),
    onMinusClick: () => dispatch(decrement())
  };
}

dans ceci:

import { bindActionCreators } from 'redux';

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    onPlusClick: increment,
    onMinusClick: decrement
  }, dispatch);
}

ou encore plus court lorsque les noms d'accessoires correspondent aux noms des créateurs d'action:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

Si vous le souhaitez, vous pouvez certainement dispatchy ajouter à la main:

// injects increment, decrement, and dispatch itself
function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators({ increment, decrement }), // es7 spread syntax
    dispatch
  };
}

Il n'y a pas d'avis officiel sur l'opportunité de le faire ou non. connect()sert généralement de frontière entre les composants compatibles Redux et non compatibles Redux. C'est pourquoi nous pensons généralement qu'il n'a pas de sens d'injecter à la fois des créateurs d'action liés et dispatch. Mais si vous sentez que vous avez besoin de le faire, n'hésitez pas à le faire.

Enfin, le modèle que vous utilisez actuellement est un raccourci encore plus court que l'appel bindActionCreators. Lorsque tout ce que vous faites est de revenir bindActionCreators, vous pouvez omettre l'appel au lieu de le faire:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

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

peut être écrit comme ceci

export default connect(
  mapStateToProps,
  { increment, decrement } // injects increment and decrement
)(App);

Cependant, vous devrez abandonner cette belle syntaxe courte chaque fois que vous voulez quelque chose de plus personnalisé, comme le passage dispatchégalement.

Dan Abramov
la source
2
@DanAbramov btw est le deuxième paramètre en bindActionCreators(actionCreators, dispatch)option? J'ai remarqué dans votre code à la // es7 spread syntaxligne, le dispatchn'est pas passé àbindActionCreators
yonasstephen
quelle est la méthode d'incrémentation à l'intérieur?
Khurshid Ansari
La syntaxe de diffusion es7 devrait être function mapDispatchToProps(dispatch) { return { ...bindActionCreators({ increment, decrement }), dispatch }; }
Noir
6

Vous pouvez généralement mélanger et assortir en fonction de ce que vous souhaitez.

Vous pouvez passer dispatchcomme accessoire si c'est ce que vous voulez:

export default connect(mapStateToProps, (dispatch) => ({
    ...bindActionCreators({fetchUsers}, dispatch), dispatch
}))(Users);

Je ne sais pas comment fetchUsersest utilisé (comme une fonction async?), Mais vous généralement utiliser quelque chose comme bindActionCreatorsà l' auto-bind expédition et vous ne seriez pas à vous soucier de l' utilisation dispatchdirectement dans les composants connectés.

L'utilisation d'une dispatchsorte de répertoire couple le composant stupide et sans état avec redux. Ce qui peut le rendre moins portable.

Davin Tryon
la source
3
Ce que vous suggérez ne fonctionnera pas. Vous obtiendrez un non lié fetchUsersinjecté comme accessoire. La notation de raccourci ne fonctionne que lorsque vous passez un objet comme deuxième argument. Lorsque vous passez une fonction , vous devez appeler bindActionCreatorsvous - même: dispatch => ({ ...bindActionCreators({ fetchUsers }, dispatch), dispatch }).
Dan Abramov
Pourquoi se propager et passer en expédition directement dans bindActionCreators? dispatch => ( bindActionCreators({ dispatch, fetchUsers }, dispatch))
user3711421
2

Bien que vous puissiez transmettre dispatchdans le cadre de dispatchToProps, je vous recommande d'éviter d'accéder à storeou dispatchdirectement à partir de vos composants. Il semble que vous seriez mieux servi en passant un créateur d'action lié dans le deuxième argument de connectdispatchToProps

Voir un exemple que j'ai publié ici https://stackoverflow.com/a/34455431/2644281 sur la façon de transmettre un "créateur d'action déjà lié" de cette façon, vos composants n'ont pas besoin de connaître directement ou de dépendre du magasin / de la distribution .

Désolé d'être bref. Je mettrai à jour avec plus d'informations.

Erik Aybar
la source