Redux: Wie rufe ich Aktionen auf, ohne @connect zu verwenden?

Erstellt am 30. Juli 2015  ·  32Kommentare  ·  Quelle: reduxjs/redux

Ich habe einen Header-Container, der Bilddaten (URL, Größe) mit an eine Header-Komponente weitergibt

@connect(state => ({
  header: state.header
}))
export default class HeaderContainer extends Component {
 /// pass props.header data to child Header which renders image.
}

Dann habe ich eine andere Komponente, die Header-Aktionen aufrufen muss, um den Header-Status zu aktualisieren. Der Status wird nicht verwendet, sondern nur Aktionen ausgelöst. Afaik Ich muss so etwas tun:

const { dispatch } = this.props
const actions = bindActionCreators(headerActions, dispatch)

Das Problem ist, dass this.props.dispatch nur verfügbar zu sein scheint, wenn Sie den @ connect- Dekorator verwenden. Die zweite Komponente interessiert sich überhaupt nicht für den Header-Status. Muss ich hier wirklich connect verwenden oder kann es die Aktionen auf andere Weise binden? Es fühlt sich falsch an, @connect zu verwenden, wenn ich die Daten nicht verwende.

question

Hilfreichster Kommentar

Sie können dispatch manuell als Requisite an diese Komponente weitergeben.

Alle 32 Kommentare

Ich bin nicht sicher, ob es ein "richtiger" Weg ist oder nicht, aber Sie können über den Kontext auf den Shop zugreifen. Siehe die Connector -Komponente zum Beispiel:
https://github.com/gaearon/react-redux/blob/master/src/components/createConnector.js

Ich folge dir nicht. Ich kann mit @connect problemlos auf den Store zugreifen. Ich suche nach einer Möglichkeit, Aktionen in einer Komponente zu binden / aufzurufen, ohne @connect zu verwenden.

Die Funktion dispatch ist eine Methode des Speichers. Wenn Sie es in Ihrer Komponente benötigen, aber @connect nicht verwenden möchten, können Sie über den Kontext auf das Geschäft zugreifen und dessen Versandmethode verwenden:

class MyComponent extends Compoenent {
    static contextTypes = {
        store: React.PropTypes.object.isRequired,
    }

    render() {
         const { dispatch } = this.context.store
         const actions = bindActionCreators(headerActions, dispatch)
    }
}

Sie sollten den Versand von der übergeordneten Komponente oder der bereits an den Versand gebundenen Aktion weitergeben. Das ist die Art und Weise, wie ich glaube, dass der Kontext auch funktioniert, obwohl es eine Problemumgehung ist

Danke, dass du das erklärt hast! Ich verstehe es jetzt.

Sie können dispatch manuell als Requisite an diese Komponente weitergeben.

Ich bin auch ein bisschen verwirrt über dieses Problem.

Wenn ich das richtig verstehe, müssen wir entweder dispatch über Requisiten einer Komponente verfügbar haben (um Aktionen von dieser Komponente auslösen zu können) oder Aktionserstellern, die bereits an dispatch gebunden sind, von a übergeordnete Komponente. Für beide Lösungen ist jedoch eine übergeordnete Komponente erforderlich, die connect ed ist, damit der Versand über die Requisiten verfügbar ist.

Am Ende übertragen wir also nur unsere Abhängigkeit von dispatch auf eine übergeordnete Komponente. Und wie würden Sie das tun, wenn es keinen solchen connect ed Elternteil gibt?

Was wäre zum Beispiel, wenn wir uns in einer tiefen Hierarchie von Komponenten befänden:

Provider
  Router
    AppContainer
     ...
       ...
         ...
           TheComponentThatNeedDispatch

und wenn keiner der Elternteile eine Verbindung zum Redux-Status herstellen muss?

Die Bereitstellung des Versands für eine Komponente als Nebeneffekt der Verwendung von connect scheint uns in eine Situation zu bringen, in der es eine Voraussetzung ist, dass ein Elternteil connect sein muss in der Lage, dispatch eine Aktion. Dies fühlt sich seltsam an, da es keine Korrelation zwischen der Fähigkeit einer Komponente zu dispatch einer Aktion und der Notwendigkeit geben sollte, connect zum Lesen aus dem Redux-Status zu verwenden.

Ich weiß, dass wir immer noch aus einem Komponentenkontext (über store.dispatch ) auf dispatch zugreifen können, aber da dies nicht der empfohlene Weg ist ...

Was denkst du darüber?

Vielen Dank!

Dies fühlt sich seltsam an, da es keine Korrelation zwischen der Fähigkeit einer Komponente, eine Aktion auszulösen, und der Notwendigkeit geben muss, connect zum Lesen aus dem Redux-Status zu verwenden.

Warum ist es komisch? Stellen Sie sich connect als "Verbindung zu Redux herstellen" und nicht nur "Verbindung zu einem Teil des Redux-Status herstellen" vor. Dann macht es Sinn: Um in der Lage zu sein, dispatch entweder eine Komponente selbst oder einen ihrer übergeordneten Komponenten zu verwenden, muss connect() für Redux verwendet werden.

Mit der aktuellen React Redux-API ist es nicht bequem, eine Verbindung zu Redux herzustellen, ohne auch den Status auszuwählen. Sie müssten so etwas wie connect(state => ({}))(MyComponent) schreiben (leeres Objekt zurückgeben). Aus diesem Grund haben wir alternative APIs dafür untersucht, die dispatch erstklassigen Bürgern machen, und planen, eine API hinzuzufügen, um „nur die dispatch “ zu erhalten.

Macht das Sinn?

Stellen Sie sich Connect als "Connect to Redux" vor und nicht nur als "Connect to a Part of Redux State".

Macht jetzt total Sinn :).

Ich kann es kaum erwarten, die neue API zu verwenden .

Vielen Dank, Redux zu verwenden ist ein Glück!

Das sieht gut aus!

@gaearon hey Dan, kannst du mir einen Tipp geben, wie man bindActionCreators mit verschachtelten Komponenten verwendet:

"AddProduct" - verbunden mit Redux (siehe unten)
__ "Produktliste"
____ "ProductView".

Ich möchte, dass ProductView versenden kann, aber nur der Master "Produkt hinzufügen" hat:

function appState(state) {
    return {...};
}

export default connect(appState)(AddProduct)

Sie können entweder auch die verschachtelte Komponente connect() oder dispatch als Requisite übergeben.

Danke Dan, danke für deine Hilfe. Ich liebe Redux auch sehr!

eine andere Frage, wenn ich darf:
Kann ich Post-API-Post-Anfragen aus dem Reduzierer selbst platzieren?
Wenn ich in die Datenbank (Mongodb) poste, erhält das Element eine "_id", die ich in meinem Redux-Status haben möchte. Sollte der Versand als Rückruf für die POST-Anfrage erfolgen?

Dankeschön

Kann ich Post-API-Post-Anfragen aus dem Reduzierer selbst platzieren?

Auf keinen Fall müssen Reduzierstücke reine Funktionen sein, die frei von Nebenwirkungen sind.

Wenn ich in die Datenbank (Mongodb) poste, erhält das Element eine "_id", die ich in meinem Redux-Status haben möchte. Sollte der Versand als Rückruf für die POST-Anfrage erfolgen?

Ja.

Weitere Informationen finden Sie in diesem Handbuch:

danke Dan, funktioniert super (y)

Wenn ich Server-Rendering verwende, um beispielsweise den aktuellen Benutzer anzumelden,
Kann ich den asynchronen Abruf aus dem Store überspringen und auf dem Server ausführen?

Wenn ich Server-Rendering verwende, um beispielsweise den aktuellen Benutzer anzumelden, kann ich dann den asynchronen Abruf aus dem Store überspringen und auf dem Server ausführen?

Sie können einen Speicher auf dem Server erstellen, warten, bis die asynchronen Aktionen abgeschlossen sind, und dann rendern.
Siehe auch http://rackt.github.io/redux/docs/recipes/ServerRendering.html

Ich vermisse wahrscheinlich etwas Kritisches, aber warum nicht einfach den Versand während der App-Initialisierung teilweise auf alle Aktionsersteller anwenden? Dann können Sie von überall aus anrufen, ohne sich Gedanken darüber machen zu müssen, wie Sie eine Referenz zum Versand erhalten.

@mpoisot : Weil Sie beim Start der App den potenziellen Aktionsersteller kennen, importieren, binden und verteilen müssten. Dies hilft unter anderem nicht in Situationen wie der Code-Aufteilung.

@markerikson Ich muss bereits alle Reduzierungen bei App Init kennen, damit ich createStore anrufen kann. Ich stelle mir vor, in der nächsten Zeile bindAllActionCreators(store.dispatch) anzurufen.

Möglicherweise ziehen Sie am Ende etwas mehr Code ein, als Sie tatsächlich verwenden. Aber wenn das ein Problem ist, dann mach es nicht so. Oder teilen Sie Ihre Reduzierer-Sets (Reduzierer + Aktionsersteller + Selektoren) in kleinere, fokussiertere Bündel auf. Oder binden Sie nur einige Aktionsersteller.

Gibt es dafür eine schreckliche Leistungsstrafe? Oder führt es irgendwie auf einen schrecklichen Weg zur Kodierung der Hölle?

@mpoisot : nicht wirklich irgendwelche Perf Probleme, die ich mir

Die richtige Verwendung von connect führt zu einem leichten Ansatz der Abhängigkeitsinjektion. Eine "einfache" Komponente weiß nur, dass sie eine Funktion als Requisite erhält, und sollte diese Funktion nach Bedarf aufrufen. Es ist eigentlich egal, ob es sich um einen Rückruf handelt, der direkt von einer übergeordneten Komponente oder einem vorgebundenen Aktionsersteller weitergegeben wurde. Dies bedeutet, dass die Komponente auf einfache Weise wiederverwendet werden kann, und erleichtert das Testen erheblich. Wenn Sie den Store jedoch direkt importieren, wird die Komponente an diese bestimmte Store-Instanz und -Implementierung gebunden, weshalb davon abgeraten wird (gemäß den Redux-FAQ: http://redux.js.org/docs/faq/). StoreSetup.html # store-setup-multiple-store). Wenn ich richtig verstehe, wonach Sie fragen, ist dies im Grunde die gleiche Situation wie beim direkten Importieren und Referenzieren des Geschäfts.

Ein guter Punkt, eine teilweise Anwendung des Versands bei Aktionserstellern wäre gleichbedeutend mit dem Import des Geschäfts als Singleton, was verpönt ist. Ich habe versucht herauszufinden, warum, und ich habe mehrere Stellen gefunden, an denen Dan Abramov sagte, ein Singleton-Laden sei aufgrund des serverseitigen Renderns (das die meisten Leute niemals verwenden werden) verpönt, aber seltsamerweise erwähnte er nie das Testen (was jeder tun sollte oder zumindest fühle mich schlecht, wenn ich es nicht tue).

Was mich denken lässt, dass Sie sicherlich ein Store-Singleton-Objekt erstellen können, dessen Store zum Testen mit verschiedenen Stores aktualisiert werden kann? Anstatt das Geschäft selbst direkt zu exportieren, geben Sie es über StoreSingleton.getStore() und ändern Sie das aktuelle Geschäft über StoreSingleton.setStore() . Beim Testen wären Sie also nicht an eine einzelne Instanz eines Geschäfts gebunden. Ich kann jedoch erkennen, warum dies in einer Thread-Server-Umgebung nicht funktioniert.

@mpoisot Du hast gerade beschrieben, was Provider / Connect tun. ;)

Oft habe ich eine "dumme" Komponente, die eines Tages versendet werden muss (oder eine vorgebundene Aktion). Also wickle ich ihn in connect ein oder übergebe etwas von einer enthaltenden Komponente, die verbunden ist. Es fühlt sich oft nach viel Verkabelung und Übergabe von Requisiten an, nur um einen global zugänglichen Versand zu vermeiden. Für mapStateToProps () gibt es mit Provider / connect () wunderbare Leistungssteigerungen. Und für die Wiederverwendung dummer Komponenten ist es definitiv sinnvoll, die Versandlogik an die Komponente höherer Ordnung zu extrahieren.

Aber ich habe dieses Szenario oft genug getroffen, um mich zu fragen, warum. Die Antwort lautet anscheinend "So können Sie eines Tages serverseitiges Rendern durchführen". (Bitte korrigiere mich wenn ich falsch liege).

Im Moment gibt Ihnen connect() nur die Methode dispatch aus dem Geschäft von Provider , aber in Zukunft könnte sich dies möglicherweise ändern. Möglicherweise fügen wir zusätzliche Funktionen hinzu, z. B. die Integration in Entwicklertools, um Ihnen mitzuteilen, welche React-Komponente die Quelle einer Aktion war, die beispielsweise ausgelöst wird. Oder jemand erstellt eine Komponente, die den Speicher auf andere Weise erweitert, indem er den Speicher im Kontext betrachtet, ihn irgendwie erweitert und diesen erweiterten Speicher dann im Komponentenbaum weitergibt. Wenn Sie Ihre Aktionsersteller an einen Singleton-Store gebunden haben, nennen Sie möglicherweise das falsche dispatch .

Ja, einige der Experimente mit "Komponenten / eingekapseltem Zustand", die ich gesehen habe, funktionieren mit genau diesem Ansatz. Das Schöne an dieser Idee ist, dass die anderen Komponenten nicht wissen müssen, dass sich etwas geändert hat, da die Wrapper-Komponenten immer noch nur this.context.store greifen und ihre dispatch nach Bedarf verwenden.

Ich war auf beiden Seiten davon -

In meiner primären Anwendung behandeln wir den Store als Singleton und verwenden eine global verfügbare getStore() -Funktion. Wir verwenden kein serverseitiges Rendering. Wir verwenden immer noch Provider und connect für mapStateToProps .

Auf der anderen Seite habe ich eine experimentelle App erstellt, in der ich den Store (wie @jimbolla und @markerikson erwähnt) an verschiedenen Stellen innerhalb der Komponentenhierarchie dispatch als auch getState können Änderungen in der gesamten App, was bedeutet, dass sie in der gesamten App verkabelt werden müssen (entweder über context oder props ) und keine Singletons sein können.

Je nachdem, was Sie erreichen möchten, denke ich, dass das Singleton-Store-Zeug machbar ist, aber ich persönlich entferne mich langsam davon.

Ja. Sie können den Laden sicherlich als zugänglichen Singleton behandeln, aber er schränkt Sie ein, er wird nicht als idiomatisch angesehen, und ich sehe keinen wirklichen Vorteil darin.

Danke, tolles Feedback. Kann jemand einen Link posten, der eine Ladenverpackung zeigt?

@ MPoisot

Hier ist einer von Dans Kommentaren, der zeigt, wie nützlich das Umschließen von dispatch sein kann:

https://github.com/reactjs/redux/issues/822#issuecomment -145271384

Möglicherweise müssen Sie den gesamten Thread lesen, um die Motivation besser zu verstehen.

Beachten Sie insbesondere, wie dispatch verpackt ist (ich habe es hervorgehoben):

wrappeddispatch

Es tut mir leid, dass ich diesen alten Beitrag entführt habe, da ich mit der gleichen Verwirrung konfrontiert bin und eine Aktion ohne Verbindung auslösen möchte.

export default class App extends Component {
...
  componentDidMount() {
    //registering event listener
    BackgroundGeolocation.on('location', this.onLocation, this.onError);
  }

  onLocation(location) {
   //wishing to dispatch an action to update variable in store
  }

  render() {
    return (
      <Provider store={store}>
        <AlertProvider>
          <MainNavigator screenProps={{ isConnected: this.state.isConnected }} />
        </AlertProvider>
      </Provider>
    );
  }
}

Soweit ich weiß, kann ich möglicherweise keine Verbindung zum Speicher in dieser Komponente herstellen, da wir den Speicher nur konfigurieren und an Provider . Wie würde ich möglicherweise eine Aktion in meinem onLocation -Ereignis auslösen?

@isaaclem : store.dispatch(someAction) aufrufen können.

Die andere Option wäre, Ihre Komponentenstruktur so umzustrukturieren, dass einige Komponenten innerhalb des <Provider> das Geolokalisierungsverhalten im Hintergrund ausführen und auch verbunden werden können.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen