Redux: Container gegen Komponente?

Erstellt am 19. Sept. 2015  ·  46Kommentare  ·  Quelle: reduxjs/redux

In den Beispielen gibt es immer einen Ordner namens "Container" und einen Ordner namens "Komponente". Was ist der Gedanke hinter dieser Trennung?

Sind "Container" intelligente Komponenten oder leiten sie Komponenten oder etwas anderes weiter? Sollten Komponenten unter "Komponenten" immer dumm sein?

docs question

Hilfreichster Kommentar

Ich nenne components gekapselte React-Komponenten, die ausschließlich von Requisiten angetrieben werden und nicht mit Redux sprechen. Gleich wie "dumme Komponenten". Sie sollten unabhängig von Ihrem Router, Ihrer Datenabrufbibliothek usw. gleich bleiben.

Ich rufe containers Reagieren Sie auf Komponenten, die Redux, Router usw. kennen. Sie sind stärker an die App gekoppelt. Gleich wie "intelligente Komponenten".

Alle 46 Kommentare

Für mich ist container Routen-Handler, der auch den Redux-Status für diese Route abruft. Dann gebe ich meinen Zustand als Requisite weiter.

Beispielsweise,

container / properties.jsx

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect }  from 'react-redux';

import * as actions from 'actions/properties';
import Filter from 'components/properties/filter';
import List from 'components/properties/list';
import Pagination from 'components/properties/pagination';

class PropertiesContainer extends Component {
  render() {
    return (
      <section>
        <Filter filter={this.props.properties.params.filter} />
        <List items={this.props.properties.items} isFetching={this.props.properties.isFetching} />
        <Pagination pagination={this.props.properties.params.pagination} />
      </section>
    );
  }
}

function mapState(state) {
  const { properties } = state;

  return { properties };
}

function mapDispatch(dispatch) {
  return {
    actions: bindActionCreators(actions, dispatch),
  };
}

const Connector = connect(mapState, mapDispatch)(PropertiesContainer);

export default Connector;

und zum Beispiel

Komponenten / Eigenschaften / pagination.jsx

import React, { Component } from 'react';
import Pager from 'components/ui/pager';

class Pagination extends Component {
  render() {
    const { total, offset, limit } = this.props.pagination;
    const current = offset / limit;

    return (
      <Pager total={total} current={current} />
    )
  }
}

export default Pagination;

Lesen Sie von den Links, die Sie bereitgestellt haben:

"A container does data fetching and then renders its corresponding sub-component. "

Ich habe eher das Gefühl, dass "Container" tatsächlich das sind, was in Redux als "intelligente Komponenten" bezeichnet wird ... und Routen / Seiten sollten einen eigenen Ordner erhalten.

Ich bin mir nicht sicher, warum "Container" und "Routenhandler" in irgendeiner Weise zusammenhängen?

Es ist sehr üblich, die Komponenten Ihrer App nach Routen zu gruppieren. Wie @theaqua hervorhob , ist es auch üblich, jeden Routenkomponente zu einer Smart- / Containerkomponente zu machen. Wenn Sie kombinierenReduzierer verwenden, werden Sie häufig feststellen, dass Sie Status, Routen und Container nach denselben Grundsätzen aufteilen. Daher werden sie oft miteinander verbunden.

@ronag Ich dachte nicht, dass Sie Container und Seiten erstellen müssen. Warum können Sie den Routenhandler und den Redux-Konnektor nicht an einer Stelle festlegen? Es ist sehr praktisch. Halte es einfach.

In meiner Bewerbung habe ich nur 3 Routen / Seiten. Andererseits habe ich viele unabhängige Panels / Module. Es ist nicht machbar, ein riesiges connect Ich muss es zumindest in Panels aufteilen.

Wenn ich die gesamte Zuordnung vom Status zu den Requisiten und das Abrufen aller Daten in einer einzigen Datei durchführe, wäre dies nicht wartbar. Vor allem, wenn ich alle Daten am selben Ort abrufe.

Wenn Sie 3 Routen haben, benötigen Sie 3 Routen-Handler. Zum Beispiel A.jsx , B.jsx und C.jsx in /containers .

In jedem Container ziehen Sie einen Teil (nicht den gesamten!) Des Redux-Status und Aktionen werden gebunden. Dann geben Sie dies an Komponenten weiter, wie in meinem Beispiel. Es ist sehr wartbar, weil ich (und mein Team) wissen - Verbindung zu Redux herstellen und Aktionen immer in containers binden, es wird nie in components (was klein und oft zustandslos ist, wie in meinem Beispiel ).

Ich glaube, ich verstehe Ihren Vorschlag. Wie gesagt, diese 3 Dateien werden jedoch sehr kompliziert, wenn ich alle meine Daten dort abrufe. In unserer Sache wäre es im Grunde "Login, App, Logout", wo App fast alles enthalten würde.

Vielleicht bin ich zu voreingenommen für Relay wo jede Komponente einen Container hat, der beschreibt, welche Daten abgerufen werden sollen und wie sie aussehen sollen.

Ich werde Ihren Vorschlag versuchen und sehen, wo wir landen.

Ich nenne components gekapselte React-Komponenten, die ausschließlich von Requisiten angetrieben werden und nicht mit Redux sprechen. Gleich wie "dumme Komponenten". Sie sollten unabhängig von Ihrem Router, Ihrer Datenabrufbibliothek usw. gleich bleiben.

Ich rufe containers Reagieren Sie auf Komponenten, die Redux, Router usw. kennen. Sie sind stärker an die App gekoppelt. Gleich wie "intelligente Komponenten".

@gaearon : Perfekt. Das verdeutlicht die Beispiele. Vielen Dank.

@gaearon "dumme Komponenten" sind also zustandslose Komponenten, die in einer einfacheren Syntax seit React 0.14 geschrieben werden können , zum Beispiel:

var Aquarium = (props) => {
  var fish = getFish(props.species);
  return <Tank>{fish}</Tank>;
};

Hab ich recht?

@soulmachine yep.

Nicht unbedingt. Syntax ist nicht der Punkt.

"Dumme" Komponenten, auch "Präsentations" -Komponenten genannt, sind Komponenten, die alle Daten von Requisiten empfangen, Redux nicht kennen und nur das Erscheinungsbild, nicht aber das Verhalten angeben.

@theaqua @gaearon Danke!

Obwohl der Begriff "Container" in der React / Redux-Nomenklatur bereits sehr beliebt ist, haben wir beschlossen, sie in dem Projekt, an dem ich arbeite, als "Konnektoren" zu bezeichnen, um Verwechslungen mit Layout- / Grafikcontainern zu vermeiden.

Übrigens, wie man sie nennt, wurde hier zuvor besprochen. rackt / react-redux # 170. Ich behalte alles in einem components -Ordner und Präsentationsordner eine Ebene tiefer, in components/presentational , und ich denke, es ist in Ordnung, da sie wahrscheinlich nicht von anderen Teilen der App als Containern benötigt werden.

@gaearon ist also eine Komponente, die dispatch als "dumm" oder "klug" betrachtet? Es ist besonders nützlich, ein Blatt oder eine Zwischenkomponente zu haben, um eine Aktion auszulösen, anstatt das Ereignis zur obersten Komponente zurückzusprudeln, um den Versand durchzuführen.

Ja, es kann gelegentlich nützlich sein, obwohl ich solche Komponenten lieber connect() bevorzuge, damit Action Creator als Requisite eingespritzt wird. Es spielt keine Rolle, wie du es nennst :-)

Was ist, wenn Sie ein Komponentenmodul erstellen? Angenommen, ich habe ein separates Knotenmodul für unser Navigationsmenü. <NavMenu> Ich möchte, dass die Leute Code wie folgt ausführen:

import {NavMenu} from 'my-redux-aware-components';

export function myPage(props) {
  return (<div><NavMenu routes={props.routes} /></div>);
}

Nenne ich es einfach "NavMenuContainer"? das kommt mir komisch vor. Soll ich stattdessen die Komponente NavMenuComponent benennen? beide kommen mir komisch vor. In diesem Fall ruft die Komponente nur connect auf, um 1 Feld aus dem Status abzurufen. Ist es wirklich so schlimm, nur den Anruf inline zu setzen, um eine solche Verbindung herzustellen?

export default const NavMenu = connect(state => ({currentPath:state.routing.path})(React.createClas({...}));

Neugierig auf Ihre Gedanken @gaearon, wann (wenn überhaupt) es "in Ordnung" ist, nur den Verbindungsanruf zu inline ...

Es ist egal, wie du es nennst. Warum nennst du es nicht NavMenu ?

Ich verstehe die Frage nach Inlining nicht.
Es wäre hilfreich, wenn Sie zwei Ansätze vorstellen würden, die Sie vergleichen.

ok so zum beispiel.
Option 1 (2 separate Dateien, 1 für Container, 1 für Komponente)

Container / NavMenu

import {connect} from 'react-redux';
import NavMenu from '../components/NavMenu';

export default connect(state => ({currentPath:state.routing.path})(NavMenu);

Option 2 (1 einzelne Datei, die beide enthält):
Komponenten / NavMenu

import {connect} from 'react-redux';

export default connect(state => ({currentPath:state.routing.path})(React.createClass({
  render() {
      return <div>the menu {this.props.currentPath} goes here</div>;
  }
});

Was ich mit Inlining meine, ist nur eine einzige Datei (im Gegensatz zu 2 Dateien), die sowohl der Container als auch die Komponente ist, da es nur ein kleines bisschen über den aktuellen Pfad gibt, der vom Status benötigt wird. Ist dies nur etwas, das immer vermieden werden sollte, oder ist es vernünftig, dies in einfachen Fällen wie diesen zu tun?

Sicher, es ist vernünftig, dies in einfachen Fällen zu tun.

OK Cool. Wann würden Sie die Linie ziehen und sagen "OK, ich würde dies in 2 separate Dateien verschieben"?

Wenn die Komponente beginnt, Datenprobleme (Abrufen / Berechnen von Daten, Versenden von Aktionen) mit Präsentation (wie es aussieht) zu mischen. Wenn es schwierig wird, in einem anderen Kontext zu testen oder wiederzuverwenden.

@benmonro Noch ein Gedanke. Wenn Sie ein Komponentenmodul erstellen, möchten Sie diese Komponenten manchmal mit verschiedenen Teilen des Statusbaums Ihrer App verbinden oder ihre Darstellung separat mit verschiedenen Status testen. In diesem Fall würde connect in diesem Komponentenmodul diese Fähigkeit einschränken.

danke @gaearon

@sompylasar sehr guter Punkt! Vielen Dank

hmm ok nachdem ich meinen Code durchgesehen habe, um ihn umzugestalten, um ihn aufzuteilen, habe ich jetzt eine Folgefrage. Angenommen, ich habe auch einen <NavMenuItem> Container. Die <NavMenu> -Komponente muss <NavMenuItem /> als untergeordnetes Element referenzieren. Sollte ich nur import NavMenuItem from '../containers/NavMenuItem' in der NavMenu-Komponente ausführen? Wie wirkt sich dies auf die Testbarkeit @sompylasar aus?

Ich würde das NavMenuItem zu einer reinen Präsentationskomponente machen, in die alle benötigten Daten über Requisiten von NavMenu übertragen werden. Dies würde es ermöglichen, es separat zu testen. Sie hätten also zwei Präsentationskomponenten (NavMenu, NavMenuItem) und eine verbundene Komponente (connect (...) (NavMenuItem)).

Eine Sache, die mir in dieser Diskussion fehlt: Wenn Sie sie in einer Datei haben, können Sie kein flaches Rendering zum Testen verwenden. Ich habe gesehen, dass Leute sowohl die Präsentationskomponente als auch die Containerkomponente verfügbar gemacht haben, um dies zu umgehen, und dann separat getestet haben. In diesem Fall hätte ich lieber zwei Dateien, um deutlich zu machen, dass dies zwei Dinge sind. Dies unterstreicht auch die Trennung der Bedenken hier und die Tatsache, dass die Präsentationskomponente unabhängig und wiederverwendbar ist.

FWIW Ich habe den Artikel zu Präsentations- und Containerkomponenten aktualisiert, um meine aktuellen Überlegungen widerzuspiegeln.

Wir raten nicht mehr davon ab, Containerkomponenten in den aktualisierten Dokumenten zu erstellen.
http://redux.js.org/docs/basics/UsageWithReact.html

@gaearon in Ihrem aktuellen Beispiel im Redux-Dokument scheint, dass Komponenten Container als
Liege ich falsch? Wie kann dies die Testbarkeit einer dummen Komponente beeinflussen, die darin eine intelligente macht?
Ich finde jedoch nicht die Möglichkeit, Komponenten zu den neuesten in der Hierarchie zu machen ...

Ich habe eine App, die eine Simple Data List-Komponente (Dumb) rendert.
Darin muss jeder Artikel mit dem Geschäft verbunden sein, also ist es ein Smart.

Laut dem Dokument ist es in Ordnung, aber kann es ein Problem bringen?

Danken!

Wie kann dies die Testbarkeit einer dummen Komponente beeinflussen, die darin eine intelligente macht?

Dies erschwert das Einrichten von Tests etwas (Sie müssen auch den Speicher initialisieren). Wenn dies eine Unannehmlichkeit ist, extrahieren Sie mehr Präsentationskomponenten, die children akzeptieren, damit Sie Containerkomponenten darin übergeben können. Im Allgemeinen liegt die Aufteilung bei Ihnen, und Sie müssen die Kompromisse (einfache Schreibweise, Refactoring, Tests usw.) bewerten und auswählen, wie Sie die Komponenten für sich selbst trennen möchten.

Ok, also gibt es keinen richtigen Weg. Wir müssen von Fall zu Fall bewerten. Viele
Vielen Dank!!

Il lunedì 8 febbraio 2016, Dan Abramov [email protected] ha
scritto:

Wie kann sich dies auf die Testbarkeit einer dummen Komponente auswirken, die darin gerendert wird?
ein kluger?

Dies macht das Einrichten des Testens etwas schwieriger (Sie müssen es initialisieren
der Laden auch). Wenn dies eine Unannehmlichkeit ist, extrahieren Sie mehr
Präsentationskomponenten, die untergeordnete Elemente akzeptieren, damit Sie Container übergeben können
Komponenten im Inneren. Im Allgemeinen liegt die Aufteilung bei Ihnen, und Sie müssen
Bewerten Sie die Kompromisse (einfache Schreibweise, Umgestaltung, Tests usw.) und
Wählen Sie, wie Sie die Komponenten selbst trennen möchten.

- -
Antworte direkt auf diese E-Mail oder sieh sie dir auf GitHub an
https://github.com/rackt/redux/issues/756#issuecomment -181143304.

Luca Colonnello
+39 345 8948718
luca. [email protected]

Was ist mit "Layout-Komponenten"? Ich meine, wenn Sie viele Container haben, die sich in einer einzelnen Komponente befinden müssen, um sie an den Router / Navigator zu übergeben, wird diese Wrapping-Komponente ein "dummer Präsentationscontainer mit Containern" sein, oder?

@ Emilios1995 Ich habe das gleiche Problem ...
Ich habe eine Seitenkomponente, die innerhalb einer Layoutkomponente verwendet wird.
Diese Layout-Komponente verfügt über Menüs, Kopf- und Fußzeilen. Der Inhalt ist das untergeordnete Element, das von Seite an Layout übergeben wird.
Menüs und Header sind Container !! Layout ist also möglicherweise ein Container, aber nicht mit dem Geschäft verbunden.

Wenn ich jedoch versuche, das Layout der Menüs und der Kopfzeile zu übergeben, habe ich eine Seite (Container), die das Layout (Komponente) rendert und Menüs und Kopfzeilen (Container) an sie übergibt.

Dabei ist die Hierarchie korrekt, aber ich muss Menüs und Überschriften auf jeder Seite wiederholen, und beide sind auf jeder Seite für mich gleich.

@ LucaColonnello Ich verstehe das Problem ohne den Code nicht ganz. Darf ich Sie bitten, eine StackOverflow-Frage mit einem einfachen Beispiel zu erstellen, das Ihr Problem veranschaulicht? Ich würde gerne einen Blick darauf werfen.

so schnell wie möglich

Il sabato 27 febbraio 2016, Dan Abramov [email protected] ha
scritto:

@LucaColonnello https://github.com/LucaColonnello Ich weiß nicht ganz
Verstehe das Problem ohne den Code. Darf ich Sie bitten, eine zu erstellen
StackOverflow-Frage mit einem einfachen Beispiel zur Veranschaulichung Ihres Problems? Ich würde
sei glücklich, einen Blick darauf zu werfen.

- -
Antworte direkt auf diese E-Mail oder sieh sie dir auf GitHub an
https://github.com/reactjs/redux/issues/756#issuecomment -189672067.

Luca Colonnello
+39 345 8948718
luca. [email protected]

Ich denke, Dans Artikel über Medium
https://medium.com/@dan_abramov/smart -and-dumme-Komponenten-7ca2f9a7c7d0 # .3y00gw1mq
klärt alle Fragen ...

2016-03-01 18:19 GMT + 01: 00 Emilio Srougo [email protected] :

@gaearon https://github.com/gaearon Es ist kein Problem, ich denke es ist
eher eine Frage, die ich hier gestellt habe:
http://stackoverflow.com/questions/35729025/should-the-route-handlers-use-containers-or-presentational-components?noredirect=1#comment59133192_35729025

- -
Antworte direkt auf diese E-Mail oder sieh sie dir auf GitHub an
https://github.com/reactjs/redux/issues/756#issuecomment -190820426.

Luca Colonnello
+39 345 8948718
luca. [email protected]

@gaearon Ich frage mich, ob eine Präsentationskomponente, wenn sie Containerkomponenten enthält, wie sie wiederverwendbar sein kann.
Zu Ihrer Information:

Ich frage mich, ob eine Präsentationskomponente, wenn sie Containerkomponenten enthält, wie sie wiederverwendbar sein kann.

Wenn alle Verwendungsszenarien einen bestimmten Container enthalten, sehe ich nicht, was daran nicht wiederverwendbar ist. Wenn nicht, akzeptieren Sie this.props.children und erstellen Sie andere Präsentationskomponenten, die bestimmte Container oder Präsentationskomponenten im Inneren übergeben.

@gaearon Ist die [Root-Komponente] Containerkomponente auf dem React-Router?

  • route.js
<Route path="/" component={Root}>
      <IndexRoute component={Main} />
      <Route path="/account/signIn" component={SignIn} />
</Route>
  • root.js
export default class Root extends React.Component {
  render() {
    return (
      <div>
        <div id="container" className="container">
          {this.props.children}
        </div>
      </div>
    );
  }

Vielen Dank.

@gaearon oben haben Sie gesagt, dass Sie es vorziehen, Komponenten zu verbinden, um Zugriff auf den Versand zu erhalten (im Gegensatz zur Weitergabe von übergeordneten Komponenten).

Wenn Sie diese Komponenten verbinden und sie auch Requisiten haben, die von den Reduzierungen zugeordnet werden könnten, die derzeit vom übergeordneten Element übergeben werden, würden Sie diese so umgestalten, dass sie von connect ? Oder verwenden Sie ownProps , um sie vom Elternteil übergeben zu lassen.

Gibt es einen Funktions- / Leistungsunterschied zwischen den beiden Optionen?

Ich habe nicht viel Erfahrung mit riesigen Redux-Projekten, aber ich habe viel über die Optimierung der React / Redux-Dateistrukturen recherchiert und nachgedacht. Lassen Sie mich wissen, ob dies sinnvoll ist oder nicht:

src/
  components/
    header/ 
      navigation.js # nav menu list
      index.js # Header component
  modules/
    header/
      actions.js # header actions (sticky scroll, collapse mobile menu, etc...)
      reducer.js # header actions reducer (export to modules index)
      index.js # HeaderContainer (connect to Header component)
    index.js # combineReducers and export default configureStore (and middleware)

ein anderes Konzept:

src/
  components/
    navigation.js
    logo.js
    link.js
    list.js
    item.js
  modules/
    header/
      actions.js # header actions 
      wrapper.js # header class (smart) component - to wrap header with functionality (was previously classified as container)
      container.js # header functional (dumb) component - to contain universal components
      index.js # header actions reducer - to export into modules rootReducer 

Oder ist es einfach besser, Komponenten, Container und Redux-Module getrennt zu halten (obwohl sie denselben Namen haben)? Vielen Dank für jede Eingabe.

Ich habe mit React-Redux-Projekten auf Unternehmensebene gearbeitet und aufgrund meiner Erfahrung kann ich eines sagen, dass es ausschließlich von Ihnen abhängt, wie Sie die Architektur Ihres Projekts definieren. Ich folge keiner der auf Containern / Komponenten basierenden Architekturvarianten, da sie in dem Sinne unpraktisch sind, dass Reacts Zweck darin besteht, wiederverwendbare komponentenbasierte Benutzeroberflächen zu erstellen.

Daher habe ich mir einen einfachen Ansatz ausgedacht, um ganze Projekte anhand von Modulen zu gruppieren, und er hat bisher in Bezug auf Skalierbarkeit, Wartbarkeit und Lesbarkeit des Codes sehr gut funktioniert.

image
image
image

Container und Smart-Component sind für mich genau gleich. Die einfache Definition lautet:
Ein Container / eine Smart-Komponente enthält JSX-Markup + Ereignishandler + API-Aufrufe + redux's connect / MSTP / MSDP.
Eine dumme Komponente ist eine rein präsentative, funktionale Komponente.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

caojinli picture caojinli  ·  3Kommentare

jbri7357 picture jbri7357  ·  3Kommentare

captbaritone picture captbaritone  ·  3Kommentare

amorphius picture amorphius  ·  3Kommentare

cloudfroster picture cloudfroster  ·  3Kommentare