web-dev-qa-db-de.com

ReactJS - Aufhebung des Zustands im Vergleich zum Beibehalten eines lokalen Zustands

In meinem Unternehmen migrieren wir das Front-End einer Webanwendung auf ReactJS . Wir arbeiten mit create -react-app (aktualisiert auf v16), ohne Redux . Jetzt stehe ich auf einer Seite Welche Struktur kann durch folgendes Bild vereinfacht werden:

 Page structure

Die von den drei Komponenten (SearchableList, SelectableList und Map) angezeigten Daten werden mit derselben Backend-Anforderung in der componentDidMount()-Methode von MainContainer abgerufen. Das Ergebnis dieser Anforderung wird dann im Status von MainContainer gespeichert und hat eine Struktur, die ungefähr der folgenden Struktur entspricht:

state.allData = {
  left: {
    data: [ ... ]
  },
  right: {
    data: [ ... ],
    pins: [ ... ]
  }
}

LeftContainer erhält als Eigenschaft state.allData.left von MainContainer und übergibt props.left.data erneut als Eigenschaft an SearchableList.

RightContainer erhält als Eigenschaft state.allData.right von MainContainer und übergibt props.right.data an SelectableList und props.right.pins an Map.

SelectableList zeigt ein Kontrollkästchen an, um Aktionen für seine Elemente zuzulassen. Immer wenn eine Aktion für ein Element der SelectableList-Komponente ausgeführt wird, kann es zu Nebeneffekten für Map-Pins kommen.

Ich habe mich entschieden, im Status von RightContainer eine Liste zu speichern, in der alle IDs der von SelectableList angezeigten Elemente enthalten sind. Diese Liste wird als Requisite an SelectableList und Map übergeben. Dann übergebe ich an SelectableList einen Rückruf, der bei jeder Auswahl die Liste der IDs in RightContainer aktualisiert. Neue Requisiten kommen sowohl in SelectableList als auch in Map an, so dass render() in beiden Komponenten aufgerufen wird.

Es funktioniert gut und hilft dabei, alles, was SelectableList und Map innerhalb von RightContainer passieren kann, beizubehalten, aber ich frage, ob dies für die lift-state-up und single-source-of-truth richtig ist. Konzepte.

Als mögliche Alternative dachte ich daran, jedem Element in _selected in MainContainer eine state.right.data -Eigenschaft hinzuzufügen und den select-Callback drei Ebenen an SelectableList zu übergeben, die alle möglichen Aktionen in MainContainer handhabt. Sobald ein Auswahlereignis eintritt, wird dies letztendlich das Laden von LeftContainer und RightContainer erzwingen, wodurch die Implementierung von Logiken wie shouldComponentUpdate() erforderlich wird, um unnötige render()-Funktionen insbesondere in LeftContainer zu vermeiden.

Welches ist/könnte die beste Lösung sein, um diese Seite in Bezug auf Architektur und Leistung zu optimieren?

Nachfolgend finden Sie einen Auszug meiner Komponenten, die Ihnen helfen, die Situation zu verstehen.

MainContainer.js

class MainContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allData: {}
    };
  }

  componentDidMount() {
    fetch( ... )
      .then((res) => {
        this.setState({
          allData: res
        });
      });
  }

  render() {
    return (
      <div className="main-container">
        <LeftContainer left={state.allData.left} />
        <RightContainer right={state.allData.right} />
      </div>
    );
  }
}

export default MainContainer;

RightContainer.js

class RightContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedItems: [ ... ]
    };
  }

  onDataSelection(e) {
    const itemId = e.target.id;
    // ... handle itemId and selectedItems ...
  }

  render() {
    return (
      <div className="main-container">
        <SelectableList
          data={props.right.data}
          onDataSelection={e => this.onDataSelection(e)}
          selectedItems={this.state.selectedItems}
        />
        <Map
          pins={props.right.pins}
          selectedItems={this.state.selectedItems}
        />
      </div>
    );
  }
}

export default RightContainer;

Danke im Voraus!

16
LucioB

Wie React docs state

Häufig müssen mehrere Komponenten dieselben sich ändernden Daten widerspiegeln. Wir Es wird empfohlen, den gemeinsam genutzten Status auf den nächstgelegenen gemeinsamen Wert hochzuheben Vorfahr.

Es sollte eine einzige "Quelle der Wahrheit" für alle Daten geben, die sich ändern in einer React-Anwendung. Normalerweise wird der Zustand zuerst dem .__ hinzugefügt. Komponente, die es zum Rendern benötigt. Wenn dann auch andere Komponenten Wenn Sie es brauchen, können Sie es bis zu ihrem nächsten gemeinsamen Vorfahren hochheben. Stattdessen Wenn Sie versuchen, den Status zwischen verschiedenen Komponenten zu synchronisieren, sollten Sie verlassen Sie sich auf den Datenfluss von oben nach unten.

Der Anhebezustand beinhaltet das Schreiben von mehr "Boilerplate" -Code als das bidirektionale verbindliche Ansätze, aber als Vorteil ist es weniger Arbeit zu finden und Fehler zu isolieren. Da jeder Zustand in einer Komponente „lebt“ und das Komponente alleine kann es ändern, die Oberfläche für Fehler ist sehr groß reduziert. Darüber hinaus können Sie jede benutzerdefinierte Logik implementieren, um sie abzulehnen oder Benutzereingabe umwandeln.

Im Wesentlichen müssen Sie also die Zustände in der Baumstruktur anheben, die in der Komponente Geschwister verbraucht werden. Die erste Implementierung, bei der Sie die selectedItems als Zustand in der RightContainer speichern, ist also völlig gerechtfertigt und ein guter Ansatz, da das übergeordnete Element keine Kenntnis davon haben muss und diese data von den beiden child-Komponenten von RightContainer und diesen beiden jetzt geteilt wird haben eine einzige Quelle der Wahrheit.

Wie in Ihrer Frage:

Als mögliche Alternative dachte ich daran, _ eine ausgewählte Eigenschaft zu .__ hinzuzufügen. jedes Element in state.right.data in MainContainer und übergeben Sie die Auswahl Rückruf drei Ebenen bis zu SelectableList, wobei alle .__ verarbeitet werden. mögliche Aktionen in MainContainer

Ich würde nicht zustimmen, dass dies ein besserer Ansatz als der erste ist, da Sie MainContainer die selectedItems oder den Handler nicht kennen müssen, um die Updates zu kennen. MainContainer unternimmt nichts über diese Zustände und gibt sie nur weiter. 

Betrachten Sie optimise on performance, Sie sprechen selbst über die Implementierung einer shouldComponentUpdate. Sie können dies jedoch vermeiden, indem Sie Ihre Komponenten erstellen, indem Sie React.PureComponent erweitern, das die shouldComponentUpdate im Wesentlichen mit einem shallow-Vergleich von state und props implementiert.

Laut den Unterlagen:

Wenn die render()-Funktion Ihrer React-Komponente dasselbe Ergebnis liefert Wenn Sie dieselben Requisiten und denselben Status haben, können Sie React.PureComponent für eine .__ verwenden. Leistungssteigerung in einigen Fällen.

Wenn jedoch mehrere tief verschachtelte Komponenten dieselben Daten verwenden, ist es sinnvoll, redux zu verwenden und diese Daten im redux-state zu speichern. Auf diese Weise ist es global für die gesamte App zugänglich und kann von Komponenten verwendet werden, die nicht direkt miteinander verbunden sind.

Betrachten Sie zum Beispiel den folgenden Fall

const App = () => {
    <Router>
         <Route path="/" component={Home}/>
         <Route path="/mypage" component={MyComp}/>
    </Router>
}

Nun hier, wenn sowohl Home als auch MyComp auf dieselben Daten zugreifen möchten. Sie können die Daten als Requisiten von App übergeben, indem Sie sie über render prop aufrufen. Es wäre jedoch leicht möglich, diese beiden Komponenten mit einer connect-Funktion wie dem Redux-Status zu verbinden

const mapStateToProps = (state) => {
   return {
      data: state.data
   }
}

export connect(mapStateToProps)(Home);

und in ähnlicher Weise für MyComp. Es ist auch einfach, Aktionen zum Aktualisieren relevanter Informationen zu konfigurieren

Es ist auch besonders einfach, Redux für Ihre Anwendung zu konfigurieren, und Sie könnten Daten speichern, die sich auf die einzelnen Elemente beziehen. Auf diese Weise können Sie auch Ihre Anwendungsdaten modularisieren

8
Shubham Khatri

Mein ehrlicher Rat dazu. Aus Erfahrung ist:

Redux ist einfach. Es ist einfach zu verstehen und zu skalieren, ABER Sie sollten Redux für bestimmte Anwendungsfälle verwenden.

Da Redux Ihre App kapselt, können Sie Dinge wie Folgendes speichern:

  • aktuelles App-Gebietsschema
  • aktueller authentifizierter Benutzer
  • aktuelle Marke von irgendwo

Dinge, die Sie auf globaler Ebene brauchen würden. react-redux erlaubt sogar einen @connect decorator für Komponenten. So wie:

@connect(state => ({ 
   locale: state.locale,
   currentUser: state.currentUser
}))
class App extends React.Component

Diese werden alle als Requisiten weitergegeben und connect kann überall in der App verwendet werden. Obwohl ich empfehle, die globalen Requisiten einfach mit dem Spread-Operator weiterzugeben

<Navbar {...this.props} />

Alle anderen Komponenten (oder "Seiten") in Ihrer App können ihren eigenen gekapselten Status ausführen. Zum Beispiel kann die Seite Benutzer ihre eigene Sache machen.

class Users extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      loadingUsers: false,
      users: [],
    };
  }
......

Sie würden über Requisiten auf das Gebietsschema und den aktuellen Benutzer zugreifen, da diese von den Container-Komponenten weitergegeben wurden.

Dieser Ansatz habe ich mehrmals gemacht und es funktioniert.

Aber , da Sie zuerst das Wissen über React wirklich konsolidieren wollten, können Sie, bevor Sie Redux ausführen, Ihren Status einfach auf der Komponente der obersten Ebene speichern und an die Kinder weitergeben.

Nachteile:

  • Sie müssen sie immer wieder in Komponenten der inneren Ebene weiterleiten
  • Um den Status von den Komponenten der inneren Ebene zu aktualisieren, müssen Sie die Funktion übergeben, die den Status aktualisiert.

Diese Nachteile sind etwas langweilig und umständlich. Deshalb wurde Redux gebaut.

Hoffe ich habe geholfen. Viel Glück

6
Lokuzt

Durch die Verwendung von Redux können Sie solche Rückrufe vermeiden und den gesamten Status in einem einzigen Geschäft beibehalten - machen Sie Ihre übergeordnete Komponente zu einer verbundenen Komponente - und machen Sie linke und rechte Komponente zu Dummköpfen - und übergeben Sie einfach die Requisiten, die Sie von Eltern zu Kind erhalten - und Sie Sie müssen sich in diesem Fall nicht um Rückrufe kümmern.

0
monkeyjs