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:
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!
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
inMainContainer
und übergeben Sie die Auswahl Rückruf drei Ebenen bis zuSelectableList
, wobei alle .__ verarbeitet werden. mögliche Aktionen inMainContainer
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 SieReact.PureComponen
t 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
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:
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:
Diese Nachteile sind etwas langweilig und umständlich. Deshalb wurde Redux gebaut.
Hoffe ich habe geholfen. Viel Glück
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.