Grundlegendes zu React-Redux und mapStateToProps ()


219

Ich versuche, die Verbindungsmethode von React-Redux und die Funktionen, die sie als Parameter verwendet, zu verstehen. Insbesondere mapStateToProps().

So wie ich es verstehe, ist der Rückgabewert von mapStateToPropsein Objekt, das vom Status abgeleitet ist (wie es sich im Geschäft befindet), dessen Schlüssel als Requisiten an Ihre Zielkomponente übergeben werden (auf die die Komponentenverbindung angewendet wird).

Dies bedeutet, dass der Status, der von Ihrer Zielkomponente verwendet wird, eine völlig andere Struktur haben kann als der Status, der in Ihrem Geschäft gespeichert ist.

F: Ist das in Ordnung?
F: Wird das erwartet?
F: Ist das ein Anti-Muster?


11
Ich möchte der Mischung keine weitere Antwort hinzufügen ... aber mir ist klar, dass niemand Ihre Frage tatsächlich beantwortet ... meiner Meinung nach ist es KEIN Anti-Muster. Der Schlüssel befindet sich im Namen mapStateTo Props. Sie übergeben schreibgeschützte Eigenschaften für eine Komponente, die verwendet werden soll. Ich verwende häufig meine Containerkomponenten, um den Status zu übernehmen und zu ändern, bevor ich ihn an die Präsentationskomponente übergebe.
Matthew Brent

3
Auf diese Weise ist meine Präsentationskomponente viel einfacher ... Ich könnte rendern this.props.someDataim Gegensatz zu this.props.someKey[someOtherKey].someData... Sinn machen?
Matthew Brent

3
Dieses Tutorial erklärt es gut genug: learn.co/lessons/map-state-to-props-readme
Ayan

Hallo Pablo, bitte überlege dir deine gewählte Antwort noch einmal.
vsync

Überlegen Sie, wie?
Pablo Barría Urenda

Antworten:


56

F: Is this ok?
A: Ja

F: Is this expected?
Ja, dies wird erwartet (wenn Sie React-Redux verwenden).

F: Is this an anti-pattern?
A: Nein, dies ist kein Anti-Muster.

Es heißt "Verbinden" Ihrer Komponente oder "Smart machen". Es ist beabsichtigt.

Sie können Ihre Komponente eine zusätzliche Zeit von Ihrem Status entkoppeln, wodurch die Modularität Ihres Codes erhöht wird. Außerdem können Sie Ihren Komponentenstatus als Teilmenge Ihres Anwendungsstatus vereinfachen, wodurch Sie das Redux-Muster einhalten können.

Stellen Sie sich das so vor: Ein Geschäft soll den gesamten Status Ihrer Anwendung enthalten.
Für große Anwendungen kann dies Dutzende von Eigenschaften enthalten, die viele Schichten tief verschachtelt sind.
Sie möchten nicht alles bei jedem Anruf herumschleppen (teuer).

Ohne mapStateToPropsoder ein Analogon davon wären Sie versucht, Ihren Zustand auf eine andere Weise zu zerlegen, um die Leistung zu verbessern / zu vereinfachen.


6
Ich glaube nicht, dass es etwas mit der Leistung zu tun hat, jeder einzelnen Komponente Zugriff auf das gesamte Geschäft zu gewähren, so groß sie auch sein mag. Das Weitergeben von Objekten beansprucht keinen Speicher, da es immer dasselbe Objekt ist. Der einzige Grund, warum eine Komponente die Teile erhält, die sie benötigt, sind wahrscheinlich zwei Gründe: (1) -Einfacherer tiefer Zugriff (2) -Vermeiden Sie Fehler, bei denen eine Komponente den Status, der nicht zu ihr gehört,
durcheinander bringen

@vsync Könnten Sie bitte erklären, wie dies einen einfacheren Deep Access ermöglicht? Meinen Sie damit, dass die lokalen Requisiten jetzt verwendet werden können, anstatt sich auf den globalen Status beziehen zu müssen, und daher besser lesbar sind?
Siddhartha

Wie kann eine Komponente den Status, der nicht zu ihr gehört, durcheinander bringen, wenn der Status als unveränderlich übergeben wird?
Siddhartha

Wenn der Zustand unveränderlich ist, ist das in Ordnung, aber als gute Praxis ist es dennoch besser, nur die für sie relevanten Teile den Komponenten auszusetzen. Dies hilft auch andere Entwickler besser verstehen , welche Teile (des Staates Objekt) zu dieser Komponente relevant sind. In Bezug auf "leichteren Zugang" ist es in gewissem Sinne einfacher, dass der Pfad zu einem tiefen Zustand direkt als Requisite an die Komponente übergeben wird und diese Komponente blind für die Tatsache ist, dass dort Redux hinter den Kulissen steht. Komponenten sollten sich nicht darum kümmern, welches Zustandsverwaltungssystem verwendet wird, und sie sollten nur mit den Requisiten arbeiten, die sie erhalten.
vsync

119

Ja, das ist richtig. Es ist nur eine Hilfsfunktion, um einfacher auf Ihre Statuseigenschaften zugreifen zu können

Stellen Sie sich vor, Sie haben einen postsSchlüssel in Ihrer Appstate.posts

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

Und Komponente Posts

Standardmäßig connect()(Posts)werden alle Statusrequisiten für die verbundene Komponente verfügbar gemacht

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

Wenn Sie das jetzt state.postsIhrer Komponente zuordnen, wird es ein bisschen schöner

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

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

mapDispatchToProps

normalerweise muss man schreiben dispatch(anActionCreator())

mit bindActionCreatorsdir kannst du es auch leichter machen wie

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

Jetzt können Sie es in Ihrer Komponente verwenden

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

Update auf actionCreators ..

Ein Beispiel für einen actionCreator: deletePost

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

So bindActionCreatorswird nur Ihre Aktionen, wickeln sie in dispatchCall. (Ich habe den Quellcode von Redux nicht gelesen, aber die Implementierung könnte ungefähr so ​​aussehen:

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

Ich denke, ich könnte etwas vermissen, aber woher kommen dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)die fetchPostsund deletePostAktionen?
Ilyo

@ilyo das sind deine Action-Schöpfer, du musst sie importieren
webdeb

2
Gute Antwort! Ich denke, es ist auch schön zu betonen, dass dieser Codeabschnitt state => state.posts(die mapStateToPropsFunktion) React mitteilt, welche Zustände bei der Aktualisierung ein erneutes Rendern der Komponente auslösen.
Miguel Péres

38

Du hast den ersten Teil richtig verstanden:

Ja mapStateToPropshat den Speicherstatus als Argument / Parameter (bereitgestellt von react-redux::connect) und wird verwendet, um die Komponente mit einem bestimmten Teil des Speicherstatus zu verknüpfen.

Mit Verknüpfung meine ich, dass das von zurückgegebene Objekt zum mapStateToPropsZeitpunkt der Erstellung als Requisiten bereitgestellt wird und jede nachfolgende Änderung über verfügbar ist componentWillReceiveProps.

Wenn Sie das Observer-Entwurfsmuster kennen, ist es genau das oder eine kleine Variation davon.

Ein Beispiel würde helfen, die Dinge klarer zu machen:

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);

Es kann eine andere Reaktionskomponente namens genannt werden itemsFilters, die die Anzeige verwaltet und den Filterstatus im Redux Store-Status beibehält. Die Demo-Komponente "hört" oder "abonniert" Redux Store-Statusfilter, sodass immer dann, wenn Filter den Status ändern (mit Hilfe von filtersComponent) reagieren -redux erkennt, dass eine Änderung aufgetreten ist, und benachrichtigt oder "veröffentlicht" alle abhörenden / abonnierten Komponenten, indem die Änderungen an componentWillReceivePropsdiese gesendet werden. In diesem Beispiel wird ein Refilter der Elemente ausgelöst und die Anzeige aktualisiert, da sich der Reaktionsstatus geändert hat .

Lassen Sie mich wissen, ob das Beispiel verwirrend oder nicht klar genug ist, um eine bessere Erklärung zu liefern.

Wie für: Dies bedeutet, dass der Status, wie er von Ihrer Zielkomponente verwendet wird, eine völlig andere Struktur haben kann als der Status, wie er in Ihrem Geschäft gespeichert ist.

Ich habe die Frage nicht verstanden, weiß aber nur, dass sich der Reaktionsstatus ( this.setState) völlig vom Redux Store-Status unterscheidet!

Der Reaktionszustand wird verwendet, um das Neuzeichnen und Verhalten der Reaktionskomponente zu handhaben. Der Reaktionszustand ist ausschließlich in der Komponente enthalten.

Der Redux Store-Status ist eine Kombination aus Redux Reducer-Status, die jeweils für die Verwaltung einer App-Logik für kleine Teile verantwortlich sind. Auf diese Reduzierungsattribute kann mit Hilfe react-redux::connect@mapStateToPropsjeder Komponente zugegriffen werden! Dadurch ist der Redux-Speicherstatus für die gesamte App zugänglich, während der Komponentenstatus ausschließlich für sich selbst gilt.


5

Diese reagieren & redux Beispiel basiert off Mohamed Mellouki Vorbild. Aber mit validates verschönern und Fusseln Regeln . Beachten Sie, dass wir unsere Requisiten und Versandmethoden mithilfe von PropTypes definieren, damit unser Compiler uns nicht anschreit. Dieses Beispiel enthielt auch einige Codezeilen, die in Mohammeds Beispiel fehlten. Um connect verwenden zu können, müssen Sie es aus react-redux importieren . Dieses Beispiel auch bindet die Methode filterItems dies verhindert Umfang Probleme in der Komponente . Dieser Quellcode wurde automatisch mit JavaScript Prettify formatiert .

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);

Dieser Beispielcode ist eine gute Vorlage für einen Startplatz für Ihre Komponente.


2

React-Redux connect wird verwendet, um den Speicher für jede Aktion zu aktualisieren.

import { connect } from 'react-redux';

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

export default AppContainer;

Es ist sehr einfach und klar in diesem Blog erklärt .

Sie können das Github-Projekt klonen oder den Code aus diesem Blog kopieren und einfügen, um die Redux-Verbindung zu verstehen.


gute manuelle formapStateToProps thegreatcodeadventure.com/…
zloctb

1

Hier ist eine Übersicht / Boilerplate zur Beschreibung des Verhaltens von mapStateToProps:

(Dies ist eine stark vereinfachte Implementierung dessen, was ein Redux-Container tut.)

class MyComponentContainer extends Component {
  mapStateToProps(state) {
    // this function is specific to this particular container
    return state.foo.bar;
  }

  render() {
    // This is how you get the current state from Redux,
    // and would be identical, no mater what mapStateToProps does
    const { state } = this.context.store.getState();

    const props = this.mapStateToProps(state);

    return <MyComponent {...this.props} {...props} />;
  }
}

und als nächstes

function buildReduxContainer(ChildComponentClass, mapStateToProps) {
  return class Container extends Component {
    render() {
      const { state } = this.context.store.getState();

      const props = mapStateToProps(state);

      return <ChildComponentClass {...this.props} {...props} />;
    }
  }
}

-2
import React from 'react';
import {connect} from 'react-redux';
import Userlist from './Userlist';

class Userdetails extends React.Component{

render(){
    return(
        <div>
            <p>Name : <span>{this.props.user.name}</span></p>
            <p>ID : <span>{this.props.user.id}</span></p>
            <p>Working : <span>{this.props.user.Working}</span></p>
            <p>Age : <span>{this.props.user.age}</span></p>
        </div>
    );
 }

}}

 function mapStateToProps(state){  
  return {
    user:state.activeUser  
}

}}

  export default connect(mapStateToProps, null)(Userdetails);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.