260 votes

Comprendre React-Redux et mapStateToProps()

J'essaie de comprendre la méthode connect de react-redux, et les fonctions qu'elle prend comme paramètres. En particulier mapStateToProps() .

D'après ce que je comprends, la valeur de retour de la fonction mapStateToProps sera un objet dérivé de state (puisqu'il vit dans le magasin), dont les clés seront transmises à votre composant cible (le composant auquel connect est appliqué) en tant que props.

Cela signifie que l'état consommé par votre composant cible peut avoir une structure très différente de celle de l'état stocké dans votre magasin.

Q : Est-ce que ça va ?
Q : Est-ce que cela est prévu ?
Q : Est-ce un anti-modèle ?

17 votes

Je ne veux pas ajouter une autre réponse au mélange... mais je réalise que personne ne répond réellement à votre question... à mon avis, c'est PAS un anti-modèle. La clé est dans le nom mapStateTo. Props vous transmettez des propriétés en lecture seule pour un composant à consommer. J'utilise souvent mes composants conteneurs pour prendre l'état et le modifier avant de le transmettre au composant de présentation.

3 votes

De cette façon, mon élément de présentation est beaucoup plus simple... je pourrais rendre... this.props.someData à l'opposé de this.props.someKey[someOtherKey].someData ... ont un sens ?

7 votes

Ce tutoriel l'explique suffisamment bien : learn.co/lessons/map-state-to-props-readme

128voto

webdeb Points 1383

Oui, c'est correct. C'est juste une fonction d'aide pour avoir un moyen plus simple d'accéder à vos propriétés d'état.

Imaginez que vous avez un posts dans votre application state.posts

state.posts //
/*    
{
  currentPostId: "",
  isFetching: false,
  allPosts: {}
}
*/

Et composant Posts

Par défaut connect()(Posts) rendra tous les props d'état disponibles pour le composant connecté

const Posts = ({posts}) => (
  <div>
    {/* access posts.isFetching, access posts.allPosts */}
  </div> 
)

Maintenant, quand vous mettez en correspondance le state.posts à votre composant il devient un peu plus agréable

const Posts = ({isFetching, allPosts}) => (
  <div>
    {/* access isFetching, allPosts directly */}
  </div> 
)

connect(
  state => state.posts
)(Posts)

mapDispatchToProps

normalement, vous devez écrire dispatch(anActionCreator())

con bindActionCreators vous pouvez aussi le faire plus facilement comme

connect(
  state => state.posts,
  dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)
)(Posts)

Vous pouvez maintenant l'utiliser dans votre composant

const Posts = ({isFetching, allPosts, fetchPosts, deletePost }) => (
  <div>
    <button onClick={() => fetchPosts()} />Fetch posts</button>
    {/* access isFetching, allPosts directly */}
  </div> 
)

Mise à jour sur les créateurs d'action..

Un exemple d'un créateur d'action : deletePost

const deletePostAction = (id) => ({
  action: 'DELETE_POST',
  payload: { id },
})

Donc, bindActionCreators va juste prendre vos actions, les envelopper dans dispatch appel. (Je n'ai pas lu le code source de redux, mais l'implémentation pourrait ressembler à quelque chose comme ceci :

const bindActionCreators = (actions, dispatch) => {
  return Object.keys(actions).reduce(actionsMap, actionNameInProps => {
    actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))
    return actionsMap;
  }, {})
}

0 votes

Je pense que je pourrais manquer quelque chose, mais où est-ce que dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch) obtient le fetchPosts y deletePost des actions passées de ?

0 votes

@ilyo ce sont vos créateurs d'actions, vous devez les importer

2 votes

Bonne réponse ! Je pense qu'il est également bon de souligner que ce morceau de code state => state.posts (le mapStateToProps ) indiquera à React quels états déclencheront un nouveau rendu du composant lorsqu'il sera mis à jour.

77voto

Richard Strickland Points 414

Q : Is this ok?
A : oui

Q : Is this expected?
Oui, c'est prévu (si vous utilisez react-redux).

Q : Is this an anti-pattern?
R : Non, ce n'est pas un anti-modèle.

Cela s'appelle "connecter" votre composant ou "le rendre intelligent". C'est une question de conception.

Il vous permet de découpler votre composant de votre état une fois de plus ce qui augmente la modularité de votre code. Il vous permet également de simplifier l'état de votre composant comme un sous-ensemble de l'état de votre application, ce qui, en fait, vous aide à respecter le modèle Redux.

Pensez-y de la manière suivante : un magasin est censé contenir les éléments suivants tout le site l'état de votre application.
Pour les grandes applications, il peut s'agir de dizaines de propriétés imbriquées sur plusieurs couches.
Vous ne voulez pas transporter tout cela à chaque appel (coûteux).

Sans mapStateToProps ou un analogue de celui-ci, vous seriez tenté de découper votre état d'une autre manière pour améliorer les performances/simplifier.

9 votes

Je ne pense pas que le fait de donner à chaque composant l'accès à l'ensemble du magasin, aussi grand soit-il, ait quoi que ce soit à voir avec les performances. Le fait de faire circuler des objets n'occupe pas de mémoire puisque c'est toujours l même objet. La seule raison d'apporter à un composant les pièces dont il a besoin est probablement 2 raisons : (1) - Un accès en profondeur plus facile (2) - Éviter les bogues où un composant pourrait perturber un état qui ne lui appartient pas.

0 votes

@vsync Pourriez-vous expliquer comment cela permet de faciliter l'accès en profondeur ? Voulez-vous dire que les props locaux peuvent maintenant être utilisés au lieu de devoir r

0 votes

Si l'état est immuable, je suppose que c'est bien, mais tout de même, en tant que bonne pratique, il est préférable d'exposer aux composants uniquement les parties qui les concernent. Cela permet également aux autres développeurs de mieux comprendre quelles parties (de l'environnement de travail de l état ) sont pertinents pour ce composant. En ce qui concerne "l'accès plus facile", c'est plus facile dans le sens où le chemin vers un état profond est directement passé au composant en tant que prop, et ce composant est aveugle au fait qu'il y a Redux dans les coulisses. Les composants ne devraient pas se soucier du système de gestion d'état utilisé, et ils devraient travailler uniquement avec les accessoires qu'ils reçoivent.

45voto

Mohamed Mellouki Points 516

Tu as raison pour la première partie :

Oui mapStateToProps a l'état du magasin comme argument/paramètre (fourni par react-redux::connect ) et il est utilisé pour lier le composant à certaines parties de l'état du magasin.

Par liaison, j'entends l'objet renvoyé par mapStateToProps sera fourni au moment de la construction en tant qu'étais et tout changement ultérieur sera disponible par le biais du site Web de la Commission européenne. componentWillReceiveProps .

Si vous connaissez le modèle de conception Observer, c'est exactement cela ou une petite variation de celui-ci.

Un exemple aiderait à rendre les choses plus claires :

import React, {
    Component,
} from 'react-native';

class ItemsContainer extends Component {
    constructor(props) {
        super(props);

        this.state = {
            items: props.items, //provided by connect@mapStateToProps
            filteredItems: this.filterItems(props.items, props.filters),
        };
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            filteredItems: this.filterItems(this.state.items, nextProps.filters),
        });
    }

    filterItems = (items, filters) => { /* return filtered list */ }

    render() {
        return (
            <View>
                // display the filtered items
            </View>
        );
    }
}

module.exports = connect(
    //mapStateToProps,
    (state) => ({
        items: state.App.Items.List,
        filters: state.App.Items.Filters,
        //the State.App & state.App.Items.List/Filters are reducers used as an example.
    })
    // mapDispatchToProps,  that's another subject
)(ItemsContainer);

Il peut y avoir un autre composant react appelé itemsFilters qui gèrent l'affichage et la persistance de l'état du filtre dans l'état du Redux Store, le composant Demo est "à l'écoute" ou "abonné" à l'état des filtres du Redux Store, de sorte que chaque fois que l'état du filtre change (avec l'aide de filtersComponent ) react-redux détecte qu'il y a eu un changement et notifie ou "publie" tous les composants qui écoutent ou s'abonnent en envoyant les changements à leurs composants. componentWillReceiveProps qui, dans cet exemple, déclenchera un refiltre des éléments et rafraîchira l'affichage du fait que l'état de la réaction a changé.

Faites-moi savoir si l'exemple prête à confusion ou s'il n'est pas suffisamment clair pour fournir une meilleure explication.

Comme pour : Cela signifie que l'état consommé par votre composant cible peut avoir une structure très différente de celle de l'état stocké dans votre magasin.

Je n'ai pas compris la question, mais sachez simplement que l'état de réaction ( this.setState ) est totalement différent de l'état du Redux Store !

L'état react est utilisé pour gérer le redessin et le comportement du composant react. L'état de réaction est contenu dans le composant exclusivement.

L'état du Redux Store est une combinaison d'états Redux reducers, chacun étant responsable de la gestion d'une petite partie de la logique de l'application. Ces attributs de réducteurs peuvent être accédés à l'aide de la fonction react-redux::connect@mapStateToProps par n'importe quel composant ! Ce qui rend l'état du magasin Redux accessible à l'ensemble de l'application alors que l'état du composant est exclusif à lui-même.

5voto

Ce site réagir & redux L'exemple est basé sur celui de Mohamed Mellouki. Mais il est validé en utilisant embellir y règles de linting . Notez que nous définissons nos props et expédition méthodes utilisant PropTypes pour que notre compilateur ne nous crie pas dessus. Cet exemple inclut aussi quelques lignes de code qui manquaient dans l'exemple de Mohamed. de Mohamed. Pour utiliser connect, vous devez l'importer à partir de react-redux . Ce site exemple se lie à la méthode filterItems cela empêchera portée problèmes dans le site composant . Ce code source a été auto formaté en utilisant JavaScript. Prettify .

import React, { Component } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

class ItemsContainer extends Component {
  constructor(props) {
    super(props);
    const { items, filters } = props;
    this.state = {
      items,
      filteredItems: filterItems(items, filters),
    };
    this.filterItems = this.filterItems.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    const { itmes } = this.state;
    const { filters } = nextProps;
    this.setState({ filteredItems: filterItems(items, filters) });
  }

  filterItems = (items, filters) => {
    /* return filtered list */
  };

  render() {
    return <View>/*display the filtered items */</View>;
  }
}

/*
define dispatch methods in propTypes so that they are validated.
*/
ItemsContainer.propTypes = {
  items: PropTypes.array.isRequired,
  filters: PropTypes.array.isRequired,
  onMyAction: PropTypes.func.isRequired,
};

/*
map state to props
*/
const mapStateToProps = state => ({
  items: state.App.Items.List,
  filters: state.App.Items.Filters,
});

/*
connect dispatch to props so that you can call the methods from the active props scope.
The defined method `onMyAction` can be called in the scope of the componets props.
*/
const mapDispatchToProps = dispatch => ({
  onMyAction: value => {
    dispatch(() => console.log(`${value}`));
  },
});

/* clean way of setting up the connect. */
export default connect(mapStateToProps, mapDispatchToProps)(ItemsContainer);

Cet exemple de code est un bon modèle de départ pour votre composant.

2voto

ArunValaven Points 545

React-Redux connect est utilisé pour mettre à jour le magasin pour chaque action.

import { connect } from 'react-redux';

const AppContainer = connect(  
  mapStateToProps,
  mapDispatchToProps
)(App);

export default AppContainer;

C'est très simplement et clairement expliqué dans ce blog .

Vous pouvez cloner le projet github ou copier-coller le code de ce blog pour comprendre la connexion Redux.

0 votes

Bon manuel formapStateToProps thegreatcodeadventure.com/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X