React: KomponenteDidReceiveProps Bitte

Erstellt am 27. Feb. 2015  ·  94Kommentare  ·  Quelle: facebook/react

Ich möchte demütig um einen ComponentDidReceiveProps-Hook bitten, oft möchte ich etwas sowohl für ComponentWillMount als auch für ComponentWillReceiveProps tun, aber da this.props noch nicht gesetzt wurde, bin ich gezwungen, Requisiten herumzureichen, anstatt direkt daraus zu lesen this.props .

Vor dem neuen Haken

componentWillMount() {
  this.setup(this.props.id);
}

componentWillReceiveProps(next) {
  this.setup(next.id);
}

setup(id) {
  UserActions.load(id);
}

Nach Neuem Haken

componentWillMount() {
  this.setup();
}

componentDidReceiveProps() {
  this.setup();
}

setup() {
  UserActions.load(this.props.id);
}

In diesem einfachen Beispiel mag es wie eine kleine Sache erscheinen, aber oft geht die Übergabe von Requisiten tief und anstatt bequem auf this.props zu verweisen, ist man gezwungen, die Requisiten durch die gesamte Komponente zu verteilen.

Erwägen Sie das Hinzufügen von componentDidReceiveProps als Hook, um denselben Code zu nutzen, der in componentWillMount verwendet wird, ohne beide dazu zu zwingen, Requisiten in der gesamten Komponente zu installieren.

Hilfreichster Kommentar

@syranide Das

Alle 94 Kommentare

Warum nicht setup(props) ?

Wenn ich meine eigenen Projekte durchschaue, kann ich sehen, dass ich dies getan habe, wo ich ähnliche Bedürfnisse hatte (ein anderer leitet einen Teil des Zustands basierend auf Requisiten ab) bei der Wiederverwendung, ohne das Wissen zu duplizieren, welche Requisiten benötigt werden:

setup(props) {
  props = props || this.props
  UserActions.load(props.id)
}

@syranide Das

+1 scheint ein Haufen unnötiger Verkabelung in der App mit dem aktuellen Muster zu sein. Könnte ein prägnanter standardisierter Weg sein, um das Problem zu lösen. Ich habe gesehen, wie eine Menge Leute auf this.props innerhalb von ComponentWillReceiveProps verbrannt wurden, ein klares Zeichen dafür, dass es nicht intuitiv ist.

+1, das finde ich auch frustrierend.

Finde das kein Problem mehr.

+1, ich stelle auch fest, dass ich oft Requisiten herumreiche. Ähnlich wie bei @insin oben habe ich eine Weile Standardparameter verwendet:

setup(props = this.props) {
  doSomething(props);
}

Aber entschieden, dass es ein Anti-Pattern war, aufgrund der subtilen Fehler, die es verursachen kann, wenn Sie vergessen, newProps zu übergeben.

+1

Ich denke, der Grund, warum es nicht verfügbar ist, ist, dass this.props und this.state _immer_ gerenderten Werten entsprechen. Es gibt keine Möglichkeit, componentDidReceiveProps zu implementieren, das kein weiteres Rendern auslöst, ohne diese Einschränkung zu brechen.

In den meisten Fällen, wenn Sie componentWillReceiveProps , möchten Sie tatsächlich entweder eine Komponente höherer Ordnung a la Relay oder etwas wie den observe Hook, der für React 0.14 vorgeschlagen wird .

+1
Außerdem können Sie componentDidReceiveProps implementieren, ohne this.props oder this.state zu ändern. Wenn Sie nur aus diesen lesen müssen, lösen Sie kein weiteres Rendern aus. Wenn Sie innerhalb dieses vorgeschlagenen Funktionsaufrufs in Requisiten oder Zustände schreiben, schießen Sie sich selbst in den Fuß, aber das gilt für jede andere Methode im Lebenszyklus.

+1

Ich möchte auf das neue Requisiten-Ereignis antworten können, wenn shouldComponentUpdate false shouldComponentUpdate zurückgibt, daher kann ich in meinem Fall componentDidUpdate .

+1

+1

Was ist mit componentWillMount und componentWillUpdate @iammerrick

Ich möchte in der Lage sein, auf das neue props-Ereignis zu reagieren, wenn shouldComponentUpdate false zurückgibt, daher kann ich in meinem Fall ComponentDidUpdate nicht verwenden.

componentWillReceiveProps ?

+1

+1 Dies hilft bei DRY-Code und vereinfachter Logik.

Ich wäre offen für den Aufruf von componentDidReceiveProps bei der Ersteinrichtung, damit das Beispiel, das diesen Thread startet, nur eine einzelne Funktion darstellt:

componentDidReceiveProps() {
  UserActions.load(this.props.id);
}

Die Gedanken?

componentWillReceiveProps() {
  setTimeout(()=> {
    if(this.isMounted()) {
      this.componentDidReceiveProps();
    }
  });
}
componentDidReceiveProps() {
  UserActions.load(this.props.id);
}

Was denken Sie?

@YourDeveloperFriend Ich denke, es hängt davon ab, wie es im Vergleich zu anderen Lebenszyklus-Hooks und Renderverzögerungen aufgrund von kaskadierenden Timeouts bei verschachtelten Komponenten funktioniert.

Diese Art von Lebenszyklus-Hooks sollten synchron in einem Durchgang aufgerufen werden, der garantiert vor dem Rendern aufgerufen wird. Ich habe die Codebasis von React nicht studiert, gehe aber davon aus, dass das Rendern nicht bei einem Timeout aufgerufen wird.

Höchstwahrscheinlich besteht die beste Lösung darin, Hooks vor dem Rendern zu registrieren oder Komponenten zu markieren, deren Requisiten geändert wurden, sodass die Renderlogik ComponentDidReceiveProps aufruft, bevor Render aufgerufen wird.

+1 bitte. So hässlich.

Nö, mir geht es gut. Es gibt bessere Lösungen.

+1

componentDidReceiveProps() existiert bereits: Es heißt render() . Es kann jedoch einen Fall geben (wie im Beispiel von @iammerrick ), in dem Sie etwas laden/auslösen/etc. müssen, bevor Sie ein Rendern durchführen. Das bedeutet eins und eins: Du machst etwas falsch.

Wenn du Dinge tust wie

setup(id) {
    UserActions.load(id);
}

Sie führen Statefullness entweder in der Komponente oder (viel schlimmer) außerhalb ein. Warum müssen Sie jedes Mal, wenn eine Komponente Requisiten erhält, load() Daten speichern (sie sind nicht einmal garantiert neu )? Wenn Sie Lazy-Loading durchführen, ist der richtige Weg, die Daten in der Methode render() anzufordern:

render() {
    var actions = UserActions.load(id);
    if (actions) // render
    else // show spinner or return null, etc.
}

UserActions.load = function(id) {
    if (data) return data;
    else // request the data, emit change on success
}

@robyoder , die Übergabe von Argumenten an Funktionen ist nicht hässlich. Es mag zu ausführlich erscheinen, aber es ist in der von Ihnen gewählten Programmiersprache natürlich. Das Löschen der API durch Hinzufügen einer Ersatzlebenszyklusmethode, nur um die Ausführlichkeit zu reduzieren, ist in der Tat definitiv hässlich.

Also sag mir, @me-andre, warum haben wir sowohl componentWillUpdate als auch componentWillReceiveProps ?

Meiner Meinung nach, weil sie unterschiedlichen Zwecken dienen und beide hilfreich sind. Genauso wie diese beiden nicht identisch sind, ist render nicht dasselbe wie das hypothetische componentDidReceiveProps weil es aus anderen Gründen als neuen Requisiten aufgerufen wird; Außerdem erhalten Sie keinen Zugriff auf die vorherigen Requisiten.

Der Vorteil der vorherigen Requisiten besteht darin, dass Sie nicht jedes Mal Daten laden müssen. es kann bedingt sein, basierend auf den Requisiten und ob sie sich geändert haben.

Offensichtlich liegt "[Hässlichkeit] im Auge des Betrachters", denn das Hinzufügen einer richtigen Lebenszyklusmethode scheint mir eine viel sauberere Lösung zu sein.

Vielleicht gibt es noch eine andere Sichtweise...

Nehmen wir an, die Hauptziele hier sind:

(1) menschliche Fehler reduzieren – ich habe vergessen, Parameter zu übergeben oder props = props || this.props noch einmal zu verwenden
(2) um nicht wertschöpfenden Boilerplate-Code zu reduzieren - warum etwas unnötig schreiben
(3) um die kognitive Belastung zu reduzieren, zu versuchen, zu entscheiden, welche Lebenszyklusmethoden verwendet werden sollen - warum muss ich über so etwas nachdenken, warum verwende ich immer wieder leicht unterschiedliche Ansätze, je nachdem, wie ich mich an diesem Tag fühle usw.

Vielleicht liegt der Lösungsraum also darin, sowohl die Verwendung von React als auch die React-API selbst zu vereinfachen, um diese Ziele zu erreichen.

Wenn Sie mit diesen Zielen über das Problem nachdenken, könnten möglicherweise einige Lebenszyklusmethoden zusammengeführt werden, und wenn Sie wissen möchten, dass es sich um Initialisierung vs. Aktualisierung handelt, können Sie dies an der aufrufenden Signatur / den Argumenten erkennen. Beispiel: beforeRender(prevProps, prevState) oder update(prevProps, prevState) .

Persönlich habe ich das Gefühl, dass es zu viele Lebenszyklusmethoden gibt, und wenn sie konsistenter aufgerufen würden (ohne oder mit prevProps / prevState beim ersten Durchlauf und Update), könnte dies meinen Code vereinfachen und meine Produktivität steigern. Außerdem sind die Namen der Lebenszyklusmethoden ziemlich lang (ich neige dazu, sie zu kopieren / einzufügen, anstatt sie einzutippen) und es ist schwer, sich daran zu erinnern, welche werden / existierten, was mich denken lässt, dass sie vereinfacht werden könnten / sollten.

@robyoder , die kurze Antwort, warum wir sowohl componentWillUpdate als auch componentDidReceiveProps ist, dass es einen großen Unterschied zwischen ihnen gibt. Sie sind natürlich ähnlich, aber hauptsächlich darin, dass sie mit componentWill vorangestellt werden.

| | Zustand hat sich geändert | Komponente wurde nicht aktualisiert |
| --- | --- | --- |
| KomponenteWillUpdate() | ja | nein |
| KomponenteWillReceiveProps() | nein | ja |

Wie Sie vielleicht bemerkt haben, gibt es Lebenszykluspunkte / -bedingungen, bei denen eine Methode aufgerufen wird und die andere nicht. Aus diesem Grund haben wir 2 verschiedene Lebenszyklusmethoden.

componentDidReceiveProps() wie es in diesem Thema beschrieben wurde, stellt jedoch keinen Komponentenzustand oder -zustand dar und gewährt keinen Zugriff auf etwas, was componentWillReceiveProps() nicht bietet. Es fügt nur einen leichten syntaktischen Zucker hinzu, der nützlich oder einfacher erscheinen kann oder nicht - dies ist eine persönliche Präferenz, keine technische Voraussetzung . Und genau deshalb sollte es nicht hinzugefügt werden: es ist subjektiv. Sie sagen, dass Streitgespräche hässlich sind – aber Sie sagten auch, dass "[Hässlichkeit] im Auge des Betrachters liegt". Für mich scheint es, als hättest du dir selbst geantwortet.

@me-andre vielleicht antwortest du mir (@kmalakoff) und @robyoder gleichzeitig. Oder vielleicht auch nicht, aber ich werde diese Gelegenheit nutzen, um die Diskussion voranzutreiben...

Was ich angesprochen habe, war, dass vielleicht ein Denken über die aktuelle API mit diesen drei oben genannten Zielen neue Einblicke oder Perspektiven geben könnte, wie man die API vereinfachen könnte, um sie zu erreichen. Natürlich kann es sein, dass wir nach der Übung am selben Ort landen.

Lass uns die Übung durchgehen....

Nehmen wir an, dieses Thema wird verfolgt und mit +1 versehen, weil es etwas Wichtiges enthält, und sagen wir, das Hinzufügen von componentDidReceiveProps ist keine gute Idee, da es die API-Oberfläche vergrößert.

Unter Berücksichtigung der Tabelle und der 3 Ziele, die ich vorgebracht habe, hat jemand Ideen zur Vereinfachung der API und / oder eine andere Möglichkeit, den Leuten in diesem Thread das zu geben, was sie sich wünschen, und die API nicht zu erweitern (vielleicht sogar zu reduzieren / zu vereinfachen) )?

@kmalakoff , die 3 Punkte, über die Sie sprechen, sind nur

Das erste Problem, über das Sie sprechen, ist, dass Lebenszyklusmethoden unterschiedliche Argumente haben. Nun, das ist ganz natürlich - sie dienen verschiedenen Zwecken. componentWillReceiveProps nimmt Requisiten nicht, weil zum Zeitpunkt dieser Methode Vollmond war, sondern weil es darum geht, Requisiten zu erhalten, die der Komponente noch nicht zugewiesen wurden. props werden nur in Methoden übergeben, bei denen sie sich von this.props unterscheiden (können). Dies ist eigentlich ein Hinweis, kein Problem.
Das Problem Nr. 3 ist, dass es für Sie schwer ist zu entscheiden, welchen Rückruf/Ansatz Sie verwenden möchten. Nun, das ist nicht wirklich ein Problem, bis die Methoden, die ich oben bespreche, dieselbe Signatur haben. Sobald Sie sowohl state als auch this.state , props und this.props die bei den meisten Methoden gleich sind (bedeutungslos lesen), dann verwickeln Sie sich in Ersatzoptionen und Alternativen.
Das Problem Nr. 2 betrifft Boilerplate-Code... nun, React ist eine dünne Bibliothek - und deswegen ist sie schön, einfach und streng. Wenn Sie einen Wrapper erstellen möchten, der unser Leben vereinfacht und die Menge an Code, die wir täglich schreiben, reduziert - warum nicht? Veröffentlichen Sie es als Ihr eigenes npm , das von react abhängt und Sie sind fertig.

Bezüglich "es gibt zu viele Lebenszyklusmethoden" - noch nicht und wird es nie geben, wenn Sie aufhören, neue Rückrufe anzufordern, für die Sie keinen technischen Bedarf haben. Technischer Bedarf ist, wenn Sie eine komplexe Komponente implementieren und mitten in der Arbeit verstehen, dass es ohne einen hässlichen Hack

Und noch etwas...
In einer gut gestalteten React-Anwendung benötigen Sie die meisten der hier beschriebenen Methoden nicht oder verwenden sie nur sehr selten. getInitialState , componentWillMount , componentWillUnmount reichen in 99% der Fälle aus. In meinem aktuellen Projekt, das eine relativ große kommerzielle App ist, wird componentWillReceiveProps zweimal in der gesamten App verwendet. Ich würde es überhaupt nicht verwenden, aber die Umgebung (Lesebrowser) ist unvollkommen - bestimmte "zustandsbehaftete" Dinge wie scrollTop manipulieren oder sich auf Layoutberechnungen für zukünftige render s erfordert die manuelle Synchronisierung zwischen props Übergängen und DOM-Änderungen. In den meisten "normalen" Fällen müssen Sie jedoch nicht wissen, wann der Übergang von props .

@me-andre Aufgrund meiner Erfahrung mit React glaube ich, dass es Raum gibt, die API zu verbessern / zu vereinfachen. Ich bin nicht allein, weshalb dieses Problem in erster Linie angesprochen wurde und mit +1 versehen wird.

Wenn ich antworte, indem ich Feedback zu Ihrer Analyse gebe, denke ich nicht, dass dies dies wirklich voranbringen wird (weshalb ich es bisher vermieden habe), da es ein bisschen voreingenommen ist am Status quo und rechtfertigt die aktuelle API, aber Gerne gebe ich Feedback zu möglichen Lösungen! Personen, die sich mit diesem Problem befassen, suchen nach Verbesserungsideen und möglichen API-Änderungen, um die Probleme zu lösen, die durch ihre Erfahrung mit React (wie oben beschrieben) aufgeworfen wurden.

Vielleicht haben Sie Recht, dass die Community die Innovation durchführen sollte, um die API voranzutreiben und sie vielleicht wieder in den Kern zu integrieren, oder vielleicht ist die aktuelle API so wie sie ist perfekt, aber ich denke, dies ist eine großartige Gelegenheit, darüber nachzudenken, wie Veränderungen aussehen könnten das React-Team.

Der Grund, warum Sie so argumentieren, liegt vielleicht darin, dass wir nur Benutzer der Bibliothek sind, die weniger Verständnis für die aktuelle API und die darin enthaltenen Entscheidungen haben. Vielleicht könnten Sie andere React-Teammitglieder hinzuziehen, die genauso erfahren und sachkundig sind wie Sie, um zu sehen, ob wir eine andere Perspektive bekommen und vielleicht sogar eine großartige Lösung finden oder einen Konsens darüber erzielen, dass dies so gut wie möglich ist?

@kmalakoff , stellen Sie sich vor, React ist ein Motor und 4 Räder. Jetzt baut man jedes Mal, wenn man irgendwo hin will, den Rest des Autos und das fängt irgendwann an, nervig zu werden. Ansonsten beschweren Sie sich über die Notwendigkeit, sich an niedrige Motordetails zu erinnern und das Drehen der Vorderräder mit den Händen fühlt sich nicht richtig an.
Ich würde empfehlen, entweder ein komplettes Fahrzeug (ein vollwertiges Framework) zu erwerben oder die benötigten Komponenten so zu bauen, dass Sie sie im Laufe der Zeit wiederverwenden können.
Was ich in diesem Thread sehe, sind Motorbenutzer, die sich beschweren, dass der Motor kein Hydrauliksystem und keine Innenbeleuchtung hat. Was ich denke ist, dass wir einen kompletten Mist bekommen, wenn wir diese Funktionen dort hinzufügen, wo sie nicht hingehören.
React ist kein Framework: Es ist eher eine Diff-basierte Rendering-Engine, die ein leistungsstarkes Komponentensystem bereitstellt. Es verfügt über eine niedrige und minimalistische API, ist jedoch leistungsstark genug, um es Ihnen zu ermöglichen, buchstäblich alles darauf aufzubauen.
Bitte zögern Sie nicht, mich per E-Mail zu kontaktieren, wenn Sie das Gefühl haben, dass ich etwas klären muss - ich möchte nicht, dass dieser Thread zu einem Tutorial wird.

@me-andre Ich glaube, wir verstehen Ihre Position und Ihre Argumentation jetzt gut. Dankeschön! Sie haben vielleicht Recht, dass die API bereits so gut wie möglich ist, aber es besteht auch die Möglichkeit, dass sie verbessert werden kann.

Kann jemand eine Änderung der API argumentieren? z.B. Bereitstellung einer vergleichenden Analyse verschiedener Optionen (Komponente hinzufügenDidReceiveProps vs. Zusammenführen / Vereinfachen von APIs vs. keine Änderung)

Das React-Team hat das Problem beobachtet und wir diskutieren es intern. Im Prinzip neige ich immer dazu, die API-Oberfläche zu eliminieren, also tendiere ich zu den Argumenten von @me-andre. Unser Team bezeichnet componentDidReceiveProps manchmal liebevoll als "die fehlende Lebenszyklusmethode", und es gibt ernsthafte Diskussionen darüber, ob sie möglicherweise hinzugefügt werden soll. Wichtig ist, dass wir Best Practices ermöglichen, ohne schlechte Praktiken zu katalysieren.

Für uns (oder zumindest mich) wäre es am nützlichsten, ein solides Verständnis dafür zu haben, WARUM Menschen diese Lebenszyklusmethode wollen. Was versuchen Sie in diesem Lebenszyklus zu tun, der von den anderen Lebenszyklusmethoden nicht ausreichend abgedeckt wird? Warum sollte jemand UserActions.load(id); innerhalb von componentDidReceiveProps anstatt wie in https://github.com/facebook/react/issues/3279#issuecomment -163875454 vorgeschlagen zu rendern (ich kann mir vorstellen ein Grund, aber ich bin neugierig, was Ihre Gründe sind)? Gibt es andere Anwendungsfälle als das Initiieren eines Datenladens basierend auf Requisiten?

@jimfb Ich glaube, dass componentDidReceiveProps genau das ist, was ich brauche und dass andere Methoden unangemessen sind, aber ich könnte mich irren. Ich erkläre Ihnen gerne meinen Anwendungsfall.

Ich habe eine Route in meinem react-router , die so aussieht:

    <Route path="/profile/:username" component={ProfilePage} />

Ich muss die Daten für das Profil von einer externen Quelle abrufen, und um dies richtig zu tun, muss ich eine HTTP-Anfrage in der Methode componentDidMount .

Wenn ich von einem Profil zum anderen navigiere, ruft React Router leider die Konstruktormethode oder die Methode componentDidMount erneut auf (natürlich könnte dies ein Fehler sein, aber ich gehe davon aus, dass dies vorerst nicht der Fall ist). .

Ich dachte daran, dies mit dem theoretischen componentDidReceiveProps beheben. Leider existiert es noch nicht und componentWillReceiveProps wird meinen Bedürfnissen nicht gerecht.

Hinweise dazu wären sehr dankbar.

Meine Vermutung ist, dass componentDidReceiveProps genau das ist, was ich brauche.

@shea256 Können Sie erläutern, warum componentWillReceiveProps Ihren Anforderungen nicht entspricht?

@shea256 Warum muss Ihre Komponente außerdem eine HTTP-Anforderung stellen? Was enthält diese http-Anfrage? Wenn Daten, warum aktualisieren Sie Ihre Komponente nicht asynchron, wenn der Datenrückruf zurückkehrt?

@jimfb Der übliche Fall für mich ist, dass wir als Reaktion auf eine Prop-Änderung etwas asynchron laden müssen, was das Setzen eines Zustands beinhaltet, um anzuzeigen, dass das Laden stattfindet, und dann, wenn die Daten geladen werden, diesen Zustand

Sowohl das Anbringen als auch das Empfangen neuer Requisiten sollten denselben Ladezyklus auslösen, daher ist componentDidMount und componentWillReceiveProps der Ort, um die Aktualisierungsfunktion aufzurufen. render hat keine Informationen darüber, ob es sich um eine neue Requisite handelt, und wie auch immer, setState von render ist ein No-Go.

Also, ich habe eine Funktion, die das Laden übernimmt. Aber ich muss props als Parameter übergeben und vorsichtig vermeiden, this.props die für componentWillReceiveProps veraltet sind. Dies führt unweigerlich zu Fehlern, da Sie daran denken müssen, die übergebenen Requisiten zu verwenden, oder Sie erhalten subtile einseitige Fehler, wenn Änderungen eintreffen. Und die Signaturen aller beteiligten Methoden sind komplexer, da die Requisiten übergeben werden müssen.

Ja, dies ist mit der aktuellen API möglich. Aber es verursacht ungeschickten, fehleranfälligen Code, den React im Allgemeinen so gut vermeiden kann.

@jimfb Ich brauche den neuen Benutzernamen in routeParam und mit componentWillReceiveProps ich ihn noch nicht.

Ich muss eine HTTP-Anfrage stellen, um die Profildaten von einer externen Quelle zu laden (die Daten werden nicht lokal gespeichert).

Und ich kann meine Komponente in der Render-Methode aktualisieren, aber es fühlt sich etwas schmutzig an:

constructor(props) {
  super(props)

  this.state = {
    id: this.props.routeParams.id,
    profile: {}
  }
}

componentDidMount() {
  this.getProfile(this.state.id)
}

render() {
  if (this.props.routeParams.id !== this.state.id) {
    this.getProfile(this.props.routeParams.id)
  }

  return (
    <div>
      <div className="name">
       {this.state.profile.name}
      </div>
    </div>
  )
}

@grassick schrieb:

Der übliche Fall für mich ist, dass wir etwas asynchron als Reaktion auf eine Prop-Änderung laden müssen, was das Setzen eines Zustands beinhaltet, um anzuzeigen, dass das Laden stattfindet, und dann, wenn die Daten geladen werden, diesen Zustand festlegen.

Ja, genau das ist mein Anwendungsfall.

Sowohl das Mounten als auch das Empfangen neuer Requisiten sollten denselben Ladezyklus auslösen, daher ist ComponentDidMount und ComponentWillReceiveProps der Ort, um die Aktualisierungsfunktion aufzurufen.

Gut gesagt.

@shea256 kann dies nicht stattdessen mit componentWillReceiveProps ?

constructor(props) {
  super(props)

  this.state = {
    id: this.props.routeParams.id,
    profile: {}
  }
}

componentDidMount() {
  this.getProfile(this.state.id)
}

componentWillReceiveProps(nextProps) {
  let { id } = nextProps.params
  if(id !== this.state.id) {
    this.getProfile(id, (profile) => {
      this.setState({ id: id, profile: profile })
    })
  }
}

render() {
  return (
    <div>
      <div className="name">
       {this.state.profile.name}
      </div>
    </div>
  )
}

@grassick schrieb:

Der übliche Fall für mich ist, dass wir etwas asynchron als Reaktion auf eine Prop-Änderung laden müssen, was das Setzen eines Zustands beinhaltet, um anzuzeigen, dass das Laden stattfindet, und dann, wenn die Daten geladen werden, diesen Zustand festlegen.

@grassick schrieb:

render hat keine Informationen darüber, ob es sich um eine neue Requisite handelt, und setState von render ist sowieso ein No-Go.

Ich spucke hier nur aus: Wenn componentDidUpdate beim ersten Rendern (zusätzlich zu nachfolgenden Rendern) aufgerufen würde, würde das Ihren Anwendungsfall lösen? Sie könnten überprüfen, ob sich die Requisiten geändert haben, und alle Ihre Daten in componentDidUpdate laden, oder? Und beim Rendern würden Sie wissen, dass Sie Daten laden, wenn this.state.profileName != this.props.profileName . Wäre diese Alternative für Ihre Anwendungsfälle ausreichend?


Gibt es Anwendungsfälle, die Leute haben, die KEINE Komponenten beinhalten, die Daten basierend auf Requisiten laden?

@calmdev hm, ich glaube du hast recht. Ich werde das ausprobieren.

@jimfb vielleicht, obwohl ich versucht habe, componentDidUpdate und ich dachte, dass es nicht funktioniert. Ich kann noch einen Blick darauf werfen.

Und es hört sich so an, als ob ich this.state.profileName != this.props.profileName total überprüfen könnte, aber das scheint auch ein Hack zu sein, nicht wahr? An diesem Punkt, wenn componentWillReceiveProps(nextProps) am Ende funktioniert, würde ich das einfach vorziehen. Was mich jetzt stört, ist die fehlende Symmetrie bei componentDidMount . Könnte ich componentWillMount anstelle von componentDidMount ?

Ich habe einfach das Gefühl, dass der gesamte Lebenszyklus sauberer sein könnte.

@shea256 , ich habe eine Frage an dich... hast du die README für React gelesen?
Ich fühle mich nicht wohl, das zu sagen, aber wenn nicht, sollten Sie möglicherweise keine neuen Funktionen für das Tool anfordern, mit dem Sie nicht vertraut sind. Für mich klingt das sogar... absurd.
"Könnte ich componentWillMount anstelle von componentDidMount ?"
Nein, das können Sie nicht, denn wie in der Readme-Datei angegeben, wird componentWillMount aufgerufen, bevor Ihre Komponente das DOM erreicht und componentDidMount - danach. Nun, Sie können definitiv eine Methode durch eine andere ersetzen, und das würde nur Ihren Code zerstören. Der Grund, warum wir hier 2 Methoden haben, ist nicht die Ästhetik (lesen Sie "Symmetrie"). Dies liegt daran, dass wir möglicherweise eine Methode benötigen, um eine Vorbereitung vor dem Rendern durchzuführen, und die andere für eine anfängliche DOM-Abfrage / -Bearbeitung nach dem ersten Rendern. Aber selbst das ist für eine durchschnittliche React-Komponente exotisch. Normalerweise müssen Sie nur nicht manuell auf das DOM zugreifen.
"Und es hört sich so an, als könnte ich this.state.profileName != this.props.profileName absolut überprüfen, aber das scheint auch ein Hack zu sein, nicht wahr?"
Ja, Ihr gesamter Ansatz ist ein Hack. Und wer hat Ihnen gesagt, dass componentDidReceiveProps garantiert, dass die props geändert wurden? Nichts wird dies jemals tun, es sei denn, Sie definieren shouldComponentUpdate .
So funktioniert React.

@me-andre danke fürs Einspringen, aber du bist für meinen Geschmack etwas zu aggressiv. Ich glaube auch, dass Sie meine Fragen nicht verstanden haben. Ich bin ziemlich vertraut damit, was componentWillMount und componentDidMount tun. Ich warte auf die Antwort von @jimfb .

@shea256 ,
"Außerdem glaube ich nicht, dass du meine Fragen verstanden hast."
Könnten Sie bitte darauf hinweisen, wo ich den Punkt vermisse, wenn ich Ihre Fragen beantworte?
Könnten Sie bitte auch klarstellen, was Sie fragen möchten.
Außerdem sind wir nicht hier, um über Persönlichkeiten oder Geschmäcker zu diskutieren. Dies ist weder ein privates Gespräch noch ein technischer Support. Dies ist nicht einmal eine Stack-Exchange-Website, von der Sie erwarten können, dass sie Sie durch ein bestimmtes Wissensgebiet führt.
Ich spreche oft bei lokalen Treffen sowie internationalen Konferenzen über React (und nicht nur) und bin sehr offen für Wissensaustausch - wann und wo es angebracht ist. Sie können mich jederzeit direkt per E-Mail oder Skype kontaktieren.

Bezüglich Ihres Problems beim Laden von Profildaten. Sie versuchen, das Problem der Anwendung des klassischen Imperativ-Ansatzes auf ein funktional orientiertes Framework zu lösen. Eine Ansicht in React ist eine Funktion von Requisiten, Zustand und Umgebung. Wie function(state, props) { return // whatever you've computed from it } (aber die Dinge werden in der realen Welt etwas komplexer - sonst würde React überhaupt nicht existieren). Obwohl wir in 0.14 reine funktionale Komponenten erhalten, ist diese Eingabefunktion für die meisten Komponenten

Es bedeutet, dass Sie mit dem Schreiben von render() und davon ausgehen, dass Ihre Requisiten immer auf dem neuesten Stand sind und es Ihnen egal ist, ob props geändert wurden oder nicht, wie oft und wo . Ihr Fall könnte wie folgt implementiert werden:

// profile-view.js

var React = require('react');

module.exports = React.createClass({
    contextTypes: {
        app: React.PropTypes.object.isRequired
        // another option is var app = require('app')
        // or even var profiles = require('stores/profiles')
    },
    componentWillMount() {
        var {app} = this.context; // another option is to require('app')
        app.profiles.addListener('change', this.onStoreChange);
    },
    componentWillUnmount() {
        var {app} = this.context; // another option is to require('app')
        app.profiles.removeChangeListener('change', this.onStoreChange);
    },
    onStoreChange() {
        this.forceUpdate();
    },
    render() {
        var {app} = this.context;
        var profile = app.profiles.read(this.props.routeParams.id);
        if (profile) { // profile's been loaded
            return <div>{profile.name}</div>;
        } else { // not yet
            return <div>Loading...</div>;
        }
    }
});

// profiles-store.js
// app.profiles = new Profiles() on app initialization

var EventEmitter = require('events');
var {inherits} = require('util');

module.exports = Profiles;

function Profiles() {
    this.profiles = {};
}

inherits(Profiles, EventEmitter);

Profiles.prototype.read = function(id) {
    var profile = this.profiles[id];
    if (!profile) {
        $.get(`profiles/${id}`).then(profile => {
            this.profiles[id] = profile;
            this.emit('change');
        });
    }
    return profile;
};

Ziemlich einfach.
Und Sie brauchen nicht componentDidReceiveProps . Sie brauchen nicht einmal componentWillReceiveProps und ähnliche Haken. Wenn Sie jemals das Gefühl haben, sie für einen trivialen Fall zu benötigen, fehlt Ihnen das Verständnis dafür, wie man Dinge in React macht. Um es zu erhalten, verwenden Sie bitte die entsprechenden Ressourcen und werfen Sie nicht einfach den Abschnitt Issues des Repositorys in den Papierkorb . Es fühlt sich für meinen Geschmack etwas zu aggressiv an. Es fühlt sich sogar so an, als würdest du die Zeit anderer nicht respektieren.

@me-andre Es lohnt sich wahrscheinlich, deine Sprache ein wenig abzuschwächen, da sie ein bisschen konfrontativ wirken kann, obwohl du nur versuchst zu helfen. Wir möchten eine einladende Gemeinschaft für alle schaffen; Wir waren alle einmal Neulinge. Auch wenn Sie mit einigen Ihrer Punkte zur API/dem Design Recht haben, ist die Tatsache, dass so viele Leute dem Problem +1 geben, ein Hinweis darauf, dass etwas nicht stimmt, also sollten wir versuchen zu verstehen, was/warum die Leute dies wollen Lebenszyklus. Vielleicht ist das Problem, dass wir nicht ausreichend kommunizieren, wie Komponenten (Dokumentation) richtig geschrieben werden, oder vielleicht muss die API von React geändert werden - auf jeden Fall lohnt es sich, die Beschwerden/Fragen/Kommentare hier zu verstehen.

@shea256 this.state.profileName != this.props.profileName prüft, ob der interne Zustand (was die Komponente rendert) mit dem übereinstimmt, was die Eltern von der Komponente verlangen. Dies ist fast die Definition von "Komponente wird aktualisiert" oder "Komponente ist auf dem neuesten Stand", daher sehe ich es nicht als hackig an. Zumindest ist an erster Stelle nicht hackiger als die Idee "eine Datenaktualisierungsanforderung abfeuern, wenn sich die Requisite ändert und einen Setstate im Callback ausführen".

@shea256 Um es klar zu componentDidReceiveProps in Bezug auf die Entwicklerergonomie zu verstehen.

Und wer hat Ihnen gesagt, dass ComponentDidReceiveProps garantieren würde, dass die Requisiten geändert wurden?

@me-andre ist hier richtig. Die meisten Lebenszyklusmethoden garantieren nicht wirklich, dass sich etwas geändert hat; sie zeigen nur an, dass sich etwas geändert haben könnte. Aus diesem Grund müssen Sie immer überprüfen, ob previous === next erforderlich ist, wenn Sie beispielsweise eine http-Anfrage stellen. Einige Leute in diesem Thread scheinen davon auszugehen, dass sich ihr Wert geändert hat, nur weil die Lebenszyklusmethode ausgelöst wurde.

@me-andre schrieb:

Sie versuchen, das Problem der Anwendung des klassischen Imperativ-Ansatzes auf ein funktional orientiertes Framework zu lösen.

Ich denke, dies könnte die Hauptursache dafür sein, dass Leute diese neue Lebenszyklusmethode wollen, aber ich versuche immer noch herauszufinden, warum / wie Leute diese Methode verwenden möchten. Es ist durchaus möglich, dass die aktuelle Lebenszyklus-Semantik etwas falsch mit dem übereinstimmt, was die Leute normalerweise tun möchten.

Alle: Gibt es andere Anwendungsfälle für componentDidReceiveProps als "Daten asynchron als Reaktion auf eine Prop-Änderung laden"?

cc @grassick @iammerrick

@jimfb Ich habe meinen Code durchsucht und verwende auch componentWillReceiveProps , um teuer zu erstellende Objekte zu erstellen, die für das Rendern benötigt werden. Dieser Fall leidet unter dem gleichen Problem, dass er Requisiten übergeben muss und darauf achten muss, dass im Code nicht this.props verwendet wird.

@jimfb schrieb:

@me-andre Es lohnt sich wahrscheinlich, deine Sprache ein wenig abzuschwächen, da sie ein bisschen konfrontativ wirken kann, obwohl du nur versuchst zu helfen. Wir möchten eine einladende Gemeinschaft für alle schaffen; Wir waren alle einmal Neulinge. Auch wenn Sie mit einigen Ihrer Punkte zur API/dem Design Recht haben, ist die Tatsache, dass so viele Leute dem Problem +1 geben, ein Hinweis darauf, dass etwas nicht stimmt, also sollten wir versuchen zu verstehen, was/warum die Leute dies wollen Lebenszyklus. Vielleicht ist das Problem, dass wir nicht ausreichend kommunizieren, wie Komponenten (Dokumentation) richtig geschrieben werden, oder vielleicht muss die API von React geändert werden - auf jeden Fall lohnt es sich, die Beschwerden/Fragen/Kommentare hier zu verstehen.

Vielen Dank für die Erwähnung. Es ist sehr wichtig sicherzustellen, dass Sie eine einladende Gemeinschaft haben und meine Kommunikation mit Ihnen war nur angenehm.

@jimfb schrieb:

@shea256 this.state.profileName != this.props.profileName prüft, ob der interne Status (was die Komponente rendert) mit dem übereinstimmt, was das Elternelement von der Komponente rendert. Dies ist fast die Definition von "Komponente wird aktualisiert" oder "Komponente ist auf dem neuesten Stand", daher sehe ich es nicht als hackig an. Zumindest ist an erster Stelle nicht hackiger als die Idee "eine Datenaktualisierungsanforderung abfeuern, wenn sich die Requisite ändert und einen Setstate im Callback ausführen".

Ja, das erscheint vernünftig.

@jimfb schrieb:

@shea256 Um es klar zu

Dem stimme ich sehr zu. Ich habe meinen speziellen Anwendungsfall nicht gepostet, um Hilfe dazu zu erhalten. Ich habe gepostet, um einen Einblick zu geben, warum ich dachte, componentDidReceiveProps wäre nützlich.

Ich und über ein Dutzend anderer Leute, die gepostet haben, hatten eindeutig einen Instinkt, so etwas zu verwenden (was bedeutet, dass es wahrscheinlich Hunderte oder Tausende mehr gibt), was für mich darauf hindeutet, dass die API nicht so intuitiv ist, wie sie sein könnte.

@jimfb schrieb:

@me-andre ist hier richtig. Die meisten Lebenszyklusmethoden garantieren nicht wirklich, dass sich etwas geändert hat; sie zeigen nur an, dass sich etwas geändert haben könnte. Aus diesem Grund müssen Sie immer überprüfen, ob previous === next, wenn Sie beispielsweise eine http-Anfrage stellen möchten. Einige Leute in diesem Thread scheinen davon auszugehen, dass sich ihr Wert geändert hat, nur weil die Lebenszyklusmethode ausgelöst wurde.

Diese Annahme mache ich nicht. Ich habe den Scheck weggelassen, aber ich benutze jetzt einen. Aber im schlimmsten Fall würde eine zusätzliche Anfrage ausgelöst.

@jimfb schrieb:

Ich denke, dies könnte die Hauptursache dafür sein, dass Leute diese neue Lebenszyklusmethode wollen, aber ich versuche immer noch herauszufinden, warum / wie Leute diese Methode verwenden möchten. Es ist durchaus möglich, dass die aktuelle Lebenszyklus-Semantik etwas falsch mit dem übereinstimmt, was die Leute normalerweise tun möchten.

Womöglich. Darüber werde ich mir mehr Gedanken machen.

componentDidReceiveProps wäre hilfreich für einen bestimmten Anwendungsfall, den ich habe.

Ich verwende die ReactRouter- und Flux-Architektur. Wenn meine Komponente instanziiert wird, setze ich meinen Status auf einen Artikel aus einem Geschäft. Wenn dieser Store ein Änderungsereignis ausgibt, aktualisiere ich meinen Status mit derselben Abrufabfrage.

Wenn sich meine Requisiten ändern, weil ich auf derselben Route zu einer anderen Artikel-ID navigiert habe, muss ich meinen Shop erneut abfragen oder meine Komponente bleibt mit dem Status des vorherigen Artikels im Shop hängen.

Wenn componentWillReceiveProps aufgerufen wird, überprüfe ich derzeit, ob sich meine Routenparameter geändert haben, und wenn ja, rufe ich updateItemState auf. Da sich die Requisiten jedoch noch nicht wirklich geändert haben, muss ich jetzt Requisiten in meine Methode übergeben.

this.updateItemState( nextProps );

updateItemState( props ) {
    props = props || this.props;

    this.setState( {
        item: this.getItemState( props )
    } );
}

getItemState( props ) {
    props = props || this.props;

    return this.ItemStore.get( props.params[ this.paramName ] );
}

würde einfach werden

this.updateItemState();

updateItemState() {
    this.setState( {
        item: this.getItemState()
    } );
}

getItemState() {
    return this.ItemStore.get( this.props.params[ this.paramName ] );
}

Ich halte dies für einen sinnvollen Anwendungsfall.

@akinnee-gl et al: Wenn ComponentDidUpdate nach dem ersten Mount zusätzlich zu Updates gefeuert wird, würde das Ihren Anwendungsfall lösen?

@akinnee-gl , wenn Sie Flux verwenden, müssen Sie den Status nicht in einem Geschäft festlegen. Sofern es nicht absolut unmöglich ist, sollten Sie den Zustand an einem Ort beibehalten. Wenn es um Flux geht, ist dieser Ort der Laden selbst. Wenn das Geschäft Wechselgeld ausgibt, sind Sie nur forceUpdate() und dann in render() read() Ihr Geschäft.

"Wenn sich meine Requisiten ändern, weil ich auf derselben Route zu einer anderen Artikel-ID navigiert habe, muss ich meinen Shop erneut abfragen oder meine Komponente bleibt mit dem Status des vorherigen Artikels im Shop hängen."

Niemals.

Sehen Sie sich das an: Sie müssen einen bestimmten Artikel aus einem Geschäft rendern und für welchen Artikel Sie sich entscheiden, aus props . Wenn dies Ihre Anforderung ist, sollte dies im Code wie in Worten ausgedrückt werden:

    var item = this.props.store.read(this.props.id);
    return <div>{item.name}</div>;

Dies ist Ihre Komponente, mehr nicht.
Um dieses Spiel mit Flux zu ermöglichen, können Sie eine wiederverwendbare Komponente zum Binden/Entbinden von Geschäften schreiben:

<FluxWrapper store={store} component={Component} id={this.props.routeParams.id} />

var FluxWrapper = React.createClass({
    componentWillMount() {
        this.props.store.addListener('change', this.onStoreChange);
    },
    componentWillUnmount() {
        this.props.store.removeListener('change', this.onStoreChange);
    },
    onStoreChange() {
        this.forceUpdate();
    },
    render() {
        var Component = this.props.component;
        return <Component {...this.props} />;
    }
});

var Component = React.createClass({
    render() {
        var item = this.props.store.read(this.props.id);
        return <div>{item.name}</div>;
    }
});

Sehen Sie, wie winzig Ihre Komponenten werden können, wenn Sie React richtig verwenden.

Wenn Ihre Stores jedoch sehr umfangreich sind und Sie sie nicht nur read() auf jedem render() read() können, dann benötigen Sie eine Caching-Middleware. Dies kann entweder eine wiederverwendbare Komponente (ähnlich FluxWrapper ) oder ein zwischengeschalteter Proxy-Speicher sein, der die ursprüngliche Methode read() ausblendet. Proxy-Speicher sind einfach und cool - sie können nicht nur Lesevorgänge zwischenspeichern, sondern auch Änderungen unterdrücken, wenn eine Änderung des übergeordneten Speichers für den Fall nicht wichtig oder signifikant war.
Dies nennt man Komposition. Sie sollten die Komposition der Vererbung oder der Erweiterung der Funktionalität oder was auch immer vorziehen, da die Komposition skaliert .
Sobald Sie ein Problem haben, das mit einer Komponente schwer zu lösen ist, ziehen Sie bitte in Betracht, zwei oder mehr Komponenten zu verwenden, anstatt vorhandene Komponenten zu komplexieren.

@jimfb , zu meinem Ton: Ich bin kein englischer Muttersprachler und habe nicht einmal eine regelmäßige wähle ich manchmal die falschen Wörter - ich fühle einfach nicht, wie sie emotional klingen.

Interessanter Ansatz. Ich werde es mir merken. Alle offiziellen Dokumente für React sagen, dass Sie Ihre Renderfunktionen rein halten sollen (was bedeutet, dass Sie nur auf Requisiten und Zustände in den Rendermethoden zugreifen sollten). Alle Flux-Beispiele zeigen den Einstellungsstatus aus dem Geschäft.

@jimfb Das Problem mit componentDidUpdate besteht darin, dass es aus einem anderen Grund aufgerufen wird, als sich die Requisiten zu ändern. Außerdem müsste ich warten, bis die Komponente bereits aktualisiert wurde, und dann setState aufrufen, um sie erneut zu aktualisieren! Scheint ziemlich ineffizient zu sein.

@akinnee-gl componentWillReceiveProps kann auch aus anderen Gründen aufgerufen werden als sich die Requisiten zu ändern (siehe: https://github.com/facebook/react/issues/3279#issuecomment-164713518), also MÜSSEN Sie nachsehen wenn sich die Requisite trotzdem geändert hat (egal welchen Lebenszyklus Sie wählen). Wenn Sie tatsächlich asynchrone Daten erstellen, warten Sie auf die nächste Ereignisschleife, bevor Ihr Rückruf sowieso ausgelöst wird Renderfunktion, oder?

@jimfb Wenn sich der Gegenstand, auf den die Requisite verweist, bereits im Store befindet, muss er nicht erneut gerendert werden. Wenn es noch nicht im Store ist, möchten wir möglicherweise einen Ladebildschirm anzeigen. Es macht also immer noch keinen Sinn, zweimal zu rendern. Ich verstehe aber, was du sagst.

@me-andre Ich mag deinen Ansatz, während des Renderns nur aus dem Store zu lesen. Es scheint den Code zu vereinfachen. Ich befürchte jedoch, dass Sie dadurch an Effizienz verlieren. Sie verlieren die Möglichkeit, die Aktualisierung über shouldComponentUpdate zu steuern, und Sie müssen die von Ihnen erwähnte zusätzliche FluxWrapper-Komponente hinzufügen. Irgendwelche Gedanken dazu?

Ich habe die Diskussion verfolgt und möchte die dritte Option noch einmal hervorheben: (1) API ist großartig, (2) sie benötigt ComponentDidReceiveProps und (3) vielleicht gibt es eine einfachere API.

Ich betrachte das Problem als eine Gelegenheit, um zu sehen, ob wir den zugrunde liegenden Bedarf, der durch dieses Problem entsteht, lösen können, indem wir tiefere Änderungen der API durchdenken, anstatt die Diskussion auf den Lösungsraum von (1) und (2) zu beschränken.

Eine vereinfachte API könnte auf den folgenden Prinzipien basieren:

(A) Codestruktur vereinfachen / Boilerplate reduzieren
(B) Requisiten (Eingaben) vom Zustand getrennt halten (intern)

Der Hauptgrund für (A) ist, dass ich nicht wertschöpfende Boilerplate schreibe. Beispiel:

componentWillMount() { this.actuallyCheckThePropsAndMaybeDoSomething(); }
componentWillReceiveProps(nextProps) { this.actuallyCheckThePropsAndMaybeDoSomething(nextProps); }

actuallyCheckThePropsAndMaybeDoSomething(props) {
  props = props || this.props;

  let relatedProps1 = _.pick(props, KEYS1);
  if (!shallowEqual(this.relatedProps1, relatedProps1) { // changed
   this.relatedProps1 = relatedProps1;

   // do something
  }

  let relatedProps2 = _.pick(props, KEYS2);
  if (!shallowEqual(this.relatedProps1, relatedProps2) { // changed
   this.relatedProps2 = relatedProps2;

   // do something else
  }
}

Ich würde wirklich lieber Folgendes tun und keinen separaten Codepfad zum ersten Mal vs ändern:

propsUpdated(prevProps) {
  if (!shallowEqual(_.pick(prevProps || {}, KEYS1), _.pick(this.props, KEYS1)) { // changed
   // do something
  }

  if (!shallowEqual(_.pick(prevProps || {}, KEYS2), _.pick(this.props, KEYS2)) { // changed
   // do something
  }
}

Was (B) betrifft, so besteht das Hauptproblem bei der KomponenteDidUpdate wie gerade erwähnt darin, dass Sie wiederholte Methodenaufrufe auslösen können, wenn Sie den Zustand aufgrund von Eigenschaftsänderungen festlegen, da er sowohl für props (Eingaben) als auch für (internen) Zustand aufgerufen wird. Diese Codepfade scheinen besser entkoppelt zu sein, da Requisiten von außen zugeführt werden und der Zustand nach innen gesetzt wird, z. Ich habe eine vierte Möglichkeit von updated(prevProps, prevState) (ein vereinfachter Name für componentDidUpdate, da weniger Lebenszyklusmethoden eine kürzere Benennung ermöglichen könnten) versucht / in Betracht gezogen, um die Boilerplate zu reduzieren, aber ich bin mit der potenziellen redundanten Sekunde etwas unzufrieden update-Aufrufe und dass die Logik in der Praxis ziemlich unabhängig zu sein scheint.

Ausgehend von den Designprinzipien (ich bin sicher, es gibt noch mehr!) frage ich mich, ob etwas in der Art von propsUpdated und stateUpdated eine mögliche dritte Option für diese Diskussion sein könnte ?

@kmalakoff Sie müssen immer überprüfen, ob sich die Requisiten geändert haben, da wir Ihnen nie definitiv sagen können, ob sich die Requisiten geändert haben/nicht geändert haben (da Javascript keine Werttypen hat und veränderbar ist).

In diesem Sinne könnte es vielleicht shouldComponentUpdate aufrufen, um zu sagen, ob es propsDidChange oder was auch immer aufrufen soll. Allerdings separates Thema.

@jimfb nicht genau

Ich denke, er meint, dass es keine eingebaute, schnelle Möglichkeit gibt, zu überprüfen, ob this.props === nextProps da es sich möglicherweise um zwei separate Objekte handelt oder nicht.

{ a: 1 } === { a: 1 } ergibt false, da es sich um zwei separate Objekte handelt, aber

var a = { a: 1 };
var b = a;
a === b

ergibt true, weil beide tatsächlich eine Referenz auf dasselbe Objekt sind.

Wir könnten jede Eigenschaft rekursiv auf Gleichheit prüfen, aber das könnte ziemlich langsam sein. Deshalb liegt es an uns, shouldComponentUpdate umzusetzen

@kmalakoff Ich möchte diesen Thread nicht https://gist.github.com/jimfb/9ef9b46741efbb949744

TLDR: @akinnee-gl ist in seiner Erklärung genau richtig (Danke!). Mit der kleinen Korrektur, dass wir die rekursive Überprüfung sowieso nicht immer durchführen konnten (auch wenn wir wollten und die Leistung kein Problem war), da es keine Möglichkeit gibt, eine als Requisite übergebene Callback-Funktion rekursiv zu überprüfen.

Lasst uns diesen Thread aber beim Thema belassen :P.

Danke euch beiden! Hmmm, immer noch nicht ganz klar, warum die Vereinfachung der API keine Option ist, um dieses Problem zu lösen. Ich werde Kommentare zum Kern hinzufügen ...

Wenn jemand an einer breiteren Palette von Lösungen teilnehmen möchte, schließe dich uns bitte dort an!

@jimfb @calmdev Ich habe deine Vorschläge ausprobiert und verstehe jetzt genau , warum componentDidReceiveProps nicht wirklich etwas Neues hinzufügt und nicht als zusätzliche Funktion hinzugefügt werden sollte. Während ich Ihrem Wort zuvor vertraut habe, ist es für mich jetzt intuitiv nachvollziehbar, warum dies der Fall ist.

Um zu veranschaulichen, wie ich zu dieser Erkenntnis gekommen bin, möchte ich meinen neuesten Code teilen. Vielleicht kann dies auch anderen helfen.

Sehen Sie sich meine Profilseitenkomponente an:

class ProfilePage extends Component {
  static propTypes = {
    fetchCurrentProfile: PropTypes.func.isRequired,
    currentProfile: PropTypes.object.isRequired
  }

  constructor(props) {
    super(props)
    this.state = { currentProfile: {} }
  }

  componentHasNewRouteParams(routeParams) {
    this.props.fetchCurrentProfile(routeParams.id)
  }

  componentWillMount() {
    this.componentHasNewRouteParams(this.props.routeParams)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.routeParams.id !== this.props.routeParams.id) {
      this.componentHasNewRouteParams(nextProps.routeParams)
    }
    this.setState({
      currentProfile: nextProps.currentProfile
    })
  }

  render() {
    var profile = this.state.currentProfile
    return (
      <div>
        <h1>{ profile.name ? profile.name : null }</h1>
      </div>
    )
  }
}

Wenn die Komponente gemountet ist, hat sie keine Profildaten und muss das Profil von einer externen Quelle laden.

Also... Ich lasse die Funktion fetchCurrentProfile aufrufen (in componentHasNewIdProp verpackt), die die Daten von der externen Quelle abruft und dann eine Aktualisierungsaktion an Redux sendet. Der Reducer empfängt diese Aktion und aktualisiert den Anwendungsstatus, der dann die Requisiten für die ProfilePage Komponente aktualisiert.

Da die Requisiten nun aktualisiert wurden, wird die Funktion componentWillReceiveProps aufgerufen. Aber wir kennen den Kontext des Requisitenänderungsereignisses nicht, also müssen wir herausfinden, welche Requisiten (falls vorhanden) geändert wurden. Wir sehen, dass die ID dieselbe ist, sodass wir fetchCurrentProfile erneut anrufen müssen. Dann aktualisieren wir state.currentProfile damit die Komponente weiß, dass sie mit den neuen Profildaten neu rendert (ja, ich könnte dies mit Requisiten tun, aber es gibt noch einen anderen Grund, auf den ich hier nicht eingehen möchte). Zu diesem Zeitpunkt könnten wir überprüfen, ob sich props.currentProfile geändert hat, bevor wir den Status aktualisieren, aber dies ist kein teurer Vorgang, daher spielt es keine Rolle, ob wir dies überprüfen.

Dann... sagen wir, wir wollen von einem Profil zum anderen navigieren. Wir klicken auf einen Link und der Router löst die Routenänderung aus. Wir haben jetzt neue Routenparameter und die Funktion componentWillReceiveProps wird ausgelöst. Wir sehen, dass sich id geändert hat und rufen daher erneut fetchCurrentProfile auf (über componentHasNewIdProp ).

Wenn der neue Abruf zurückkommt und die Redux-Aktion absetzt, wird die currentProfile Requisite erneut aktualisiert, der Status wird dann aktualisiert und die Komponente wird mit der neuen Ansicht erneut gerendert.

Dieses Beispiel veranschaulicht, wie unterschiedliches Verhalten sein muss, wenn die Komponente bereitgestellt wird und wenn die Komponente neue Requisiten erhält. Es zeigt auch, wie im letzteren Fall die Requisiten auf Änderungen überprüft werden müssen und wie bestimmte Funktionen nur bei bestimmten Requisitenänderungen aufgerufen werden sollen.

Rückblickend wollte ich im Wesentlichen eine Funktion, die nur aktualisiert wurde, wenn sich routeParams änderte. Es ist jedoch nicht erforderlich, eine weitere Funktion hinzuzufügen, da wir mit vorhandenen Funktionen alles machen können, was wir wollen, und wir wollen den Lebenszyklus nicht verkomplizieren.

Hier könnte jedoch eine weitere Dokumentation zum Lebenszyklus, Arbeitsbeispiele usw. hilfreich sein.

Danke für eure Hilfe Jungs. Bitte lassen Sie es mich wissen, wenn ich hier etwas falsch gemacht habe. Ich hoffe, dass dies für alle hilfreich ist, die in Zukunft über diesen Thread stolpern.

@shea256 Ihr Beispiel scheint ein vernünftiger Fall dafür zu sein, keine neue API zu benötigen, da Sie ohne einen neuen API-Standpunkt erreichen können, was Sie brauchen.

Ich habe weitere Gedanken in: https://gist.github.com/jimfb/9ef9b46741efbb949744 skizziert, aber ich habe immer noch das Gefühl, dass wir in der Lage sein sollten, die API zu rationalisieren, um weniger Code zu schreiben ...

Stellen Sie sich vor, dass Sie mit der API die gleiche Funktionalität schreiben können, jedoch mit weniger Boilerplate:

class ProfilePage extends Component {
  static propTypes = {
    fetchCurrentProfile: PropTypes.func.isRequired,
    currentProfile: PropTypes.object.isRequired
  }
  state = {currentProfile: {}}; // not material to example (babel-stage-1)

  // called both on init and update
  willReceiveProps(nextProps) {
    if (!this.props || (this.props.routeParams.id !== nextProps.routeParams.id)
      nextProps.fetchCurrentProfile(nextProps.routeParams.id)
  }

  render() {
    var profile = this.props.currentProfile;
    return (
      <div>
        <h1>{ profile.name ? profile.name : null }</h1>
      </div>
    )
  }
}

Die Idee, von der ich hoffe, dass sie in Betracht gezogen wird, besteht darin, die API-Oberfläche zu reduzieren, um die Anzahl der Codepfade und Boilerplates zu reduzieren. Ich frage mich, ob die Diskussion auf der anfänglichen Bitte, etwas hinzuzufügen, verankert ist, wenn die Betrachtung aus einer anderen Perspektive vielleicht neue Wege eröffnen würde.

Dies ist nur eine Option (meine Präferenz ist ReceivedProps(prevProps), weil es idealerweise nur eine prop-bezogene Methode gibt, bei der Sie this.props verwenden könnten), aber der wichtige Teil ist, dass es einen Codepfad für die Initialisierung der . gibt Komponenten- und Prop-Änderungen statt der verschiedenen Codepfade, die wir jetzt mit unterschiedlichen API-Signaturen haben. Welche Lösung auch immer die Leute zustimmen, um besser zu sein.

Ich hoffe, dass dieses Problem eine Reduzierung der Boilerplate erreichen kann (um meinen Bedarf / mein Problem zu klären!) Lebenszyklusmethoden erheblich, Verkürzung der Methodennamen jetzt, da ES6 weit verbreitet ist und Komponenten der Weg zu sein scheinen usw.).

@akinnee-gl , eine Anwendung, die aus vielen winzigen Komponenten besteht, ist aus mehreren Gründen viel besser als aus wenigen schweren Komponenten:

  1. Dieser Ansatz verbindet sich mit dem „Prinzip der einheitlichen Verantwortung“
  2. Sie können deutlich sehen, welche Komponente was tut
  3. Sie können ganz einfach Features zusammenstellen und Komponenten erweitern, indem Sie sie umhüllen
  4. Methoden und Eigenschaften kollidieren nicht
  5. Es ist einfacher, ein Feature zu erweitern, da eine Komponente ein Feature kapselt

In Bezug auf Ihren Hinweis, dass das Lesen aus einem Speicher bei jedem Rendern ineffizient sein kann, habe ich eine Zusammenfassung erstellt, die eine grundlegende Idee zeigt, wie eine Middleware-Komponente für das Caching implementiert wird: https://gist.github.com/me-andre/0ca8b80239cd4624e6fc

Ich habe die Prinzipien / Ziele, die zu einer verbesserten API führen könnten (hoffentlich basierend auf einer Methode für empfangene Requisiten, wie in dieser Ausgabe vorgeschlagen), noch einmal überprüft:

(A) Codestruktur vereinfachen / Boilerplate reduzieren
(B) Requisiten (Eingaben) vom Zustand getrennt halten (intern)
(C) ermöglichen eine Methode zur Steuerung des Rendering einer Komponente
(D) Vereinfachen Sie die Methodenbenennung basierend auf der Annahme der Komponentenunterklassen
(E) Reduzieren Sie die Anzahl der Props-Methoden sowohl für die Initialisierung als auch für die Änderungen
(F) die props-Methode sollte this.props mit dem neuesten Wert haben

Zu einigen von ihnen gibt es Klarstellungen im Kern.

@kmalakoff Im Wesentlichen sollten wir den Umfang dieser Probleme nicht erweitern. Das Problem ist bereits komplex genug, und das Abschweifen der Konversation in ein vollständiges API-Redesign wird nicht zu handhaben sein. Sie sind herzlich eingeladen, weiterhin über diese Probleme nachzudenken, aber bitte behalten Sie diesen Thread beim Thema.

@kmalakoff Viele der von Ihnen erwähnten Punkte sind Themen anderer Probleme. Zum Beispiel wird (D) beantwortet von https://github.com/reactjs/react-future/issues/40#issuecomment -142442124 und https://github.com/reactjs/react-future/issues/40#issuecomment - 153440651. Das sind die passenden Threads, um diese Diskussion zu führen. Wenn Sie nach allgemeineren/ganzheitlichen Design-/API-Diskussionen suchen, ist das richtige Medium wahrscheinlich https://discuss.reactjs.org/

@jimfb Ich habe darüber nachgedacht, nachdem Sie vorgeschlagen haben, dies auf das Wesentliche zu verschieben, und glaube nicht, dass diese Analyselinie vom Thema abweicht ... Eine erhaltene Requisiten-Lebenszyklusmethode ermöglicht es mir, Boilerplate zu reduzieren.

Bitte hören Sie mich ... die Reduzierung von Boilerplate ist das Problem , das die Lebenszyklusmethode in diesem Problem für mich lösen könnte.

Ich glaube, dass dies auch ein wesentlicher Grund dafür sein könnte, warum Menschen an dieser Lebenszyklusmethode interessiert sind, da die aktuelle API Boilerplate mehr fördert, als uns lieb ist.

Trotzdem würde ich gerne versuchen, die API-Verbesserungen zu entkoppeln und mich beispielsweise nur darauf zu konzentrieren, den Lösungsraum rund um die Verbesserung der API in Bezug auf Requisiten in dieser Ausgabe zu erkunden.

@kmalakoff Das Thema des Threads wird durch den Titel und den ersten Beitrag definiert. Der Titel ist componentDidReceiveProps Please nicht lots of general ways to reduce boilerplate . In diesem Thread geht es darum, Boilerplate gezielt durch die Einführung einer ganz bestimmten Lebenszyklusmethode zu reduzieren. Diese Diskussion allein ist bereits nuanciert genug, ohne zusätzliche Themen (wie die Umbenennung aller Funktionen) einzuführen, die bereits in anderen Ausgaben diskutiert werden.

Ihre Punkte sind wertvoll, und ich ermutige Sie, die Diskussion zu führen. Verschieben Sie sie einfach in einen anderen Thread, denn wir möchten, dass sich die Github-Threads auf das jeweilige Thema konzentrieren. Andernfalls sind die Diskussionen zu schwer zu verfolgen/zu verwalten. Für die meisten der von Ihnen angesprochenen Themen gibt es Threads.

@jimfb warum fragen die Leute nach componentDidReceiveProps ? Der Grund, warum ich daran interessiert bin, ist die Reduzierung von Boilerplate im Zusammenhang mit Requisiten . Ich bin mir nicht sicher, wie ich das deutlicher formulieren kann, damit ich gehört und verstanden werden kann.

Sie haben nach den Problemen und Anwendungsfällen gefragt, und ich habe dies als das Problem für mich angegeben und oben einen Anwendungsfall gezeigt (als Antwort auf @shea256), der thematisch, innerhalb des Umfangs und aus meiner Sicht wichtig für die Lösung erscheint dieses Problem.

Ich habe zugestimmt, den Umfang auf allgemeine API-Probleme / -Verbesserungen auszudehnen und werde dies tun. Das verspreche ich! :zwinkern:

Zu Ihrer Information: Wie ich bereits sagte, begann ich mit dem Gedankenexperiment zu diesem Thema, weil die Argumente ein wenig zu eng fokussiert erschienen (z Ausgabe. Wie Sie wissen, müssen Sie manchmal einen Schritt zurücktreten, sich dann konzentrieren, dann aus einem anderen Blickwinkel betrachten, dann Annahmen überdenken, die zugrunde liegenden Gründe für die Anfrage untersuchen usw., um die beste Lösung für ein Problem zu finden. Hoffentlich habe ich dazu beigetragen, darauf aufmerksam zu machen, und meine Teilnahme wird dazu beitragen, dieses Problem zu unserer Zufriedenheit zu lösen! (Ich hoffe natürlich auch, dass sich die React-API nutzerfreundlicher entwickelt und diese Diskussion an anderer Stelle fortsetzen wird ... danke für die Links)

@kmalakoff , ok, um Boilerplate zu reduzieren, erstellen Sie einfach wiederverwendbare Klassen oder Komponenten, aus denen Sie Unterklassen

@me-andre das ist absolut eine Option, wenn dieses Problem nicht zu einer API-Verbesserung führt.

Dieses Problem wurde aufgeworfen, um die Diskussion über den Wunsch zu fördern, eine Änderung an der API vorzunehmen, um sie zu verbessern. Es sollte definitiv in Betracht gezogen werden, Alternativen im Clientcode zu erkunden, aber wenn ein starkes Argument dafür besteht, dass die API geändert werden sollte, wären diese Art von Problemumgehungen unnötig. Um Argumenten entgegenzuwirken, müssen auch Argumente dafür aufgestellt werden, was eine verbesserte API sein sollte, und dann gegen die aktuelle API bewertet werden, um sie zu bewerten.

Wenn Sie beispielsweise demonstrieren möchten, dass die aktuelle API ohne die Definition einer benutzerdefinierten Superklasse verwendet werden könnte, um die Boilerplate zu reduzieren (z. B. verwenden wir die API falsch oder es gibt Funktionen in der aktuellen API, die verwendet werden können ein ähnliches Maß an Reduzierung des Boilerplates usw.) oder beweisen, warum keine Verbesserung möglich ist (z. B. gibt es keine allgemeinen Lösungen, da ein wichtiger Anwendungsfall nicht in unseren API-Verbesserungsoptionen unterstützt werden konnte) usw ein Fall, dass die API so gut ist wie sie ist.

Wenn die API erfordert, dass Benutzer benutzerdefinierte Superklassen für grundlegende und allgemeine Kontrollflussmuster schreiben, verstärkt dies das Argument, dass die API verbessert werden muss.

Neugierig - was ist der Grund dafür, dass componentWillReceiveProps vor dem Aufsteigen ausgelöst wird? Wenn Sie darüber nachdenken, empfängt die Komponente wirklich Props, wenn sie initialisiert wird. Es bekommt einfach keine neuen Requisiten.

Was sind die Anwendungsfälle, in denen Sie nur beim Empfang neuer Requisiten (und nicht beim ersten Requisitenempfang) etwas auslösen möchten?

Ich könnte hier etwas Offensichtliches übersehen, aber ich versuche nur, die Standpunkte der verschiedenen Parteien in Einklang zu bringen.

Auf jeden Fall, wenn componentWillReceiveNewProps in einigen Fällen wichtig wäre, könnte man es immer noch mit einem modifizierten componentWillReceiveProps simulieren, indem man die eingehenden Requisiten überprüft.

@kmalakoff Wenn componentWillReceiveProps zum ersten Mal ausgelöst würde, würde das Ihren Standards für die API-Vereinfachung entsprechen?

componentWillReceiveProps beim Mounten nicht ausgelöst wird, ist nicht der Grund, warum die Leute nach componentDidReceiveProps fragen. Die Leute fragen nach componentDidReceiveProps weil sie alle ihre Methoden für den Zugriff auf this.props . Wenn componentWillReceiveProps aufgerufen wird, werden die nextProps übergeben, aber this.props hat sich noch nicht geändert, was bedeutet, dass wir nextProps an alle Methoden übergeben müssen, die als Antwort auf componentWillReceiveProps aufgerufen werden props = props || this.props und eine Menge props an jede Funktion, die wir aufrufen.

@shea256 gute Punkte. Unterschiedliche Codepfade für die Initialisierung im Vergleich zu Änderungen sind eine der Hauptursachen für Prop-Boilerplate. Die andere Hauptursache sind unterschiedliche Signaturen für den Umgang mit Requisiten, wie @akinnee-gl darauf hinweist.

Aus diesem Grund versuche ich, den betrachteten Lösungsraum zu erweitern (zB auch init aufrufen), da es tatsächlich eine noch bessere Lösung geben könnte, um die Prop-Boilerplate weiter zu reduzieren.

Ich hoffe, wir kommen weiter:

Vor dem neuen Haken

componentWillMount() {
  this.setup(this.props.id);
}

componentWillReceiveProps(next) {
  this.setup(next.id);
}

setup(id) {
  UserActions.load(id);
}

Nach neuem Haken (überarbeitet)

componentDidReceiveProps(prevProps) {
  UserActions.load(this.props.id);
}

oder wenn UserActions.load die aktuell geladene ID nicht überprüfen kann:

componentDidReceiveProps(prevProps) {
  if (!prevProps || (prevProps.id !== this.props.id))
    UserActions.load(this.props.id);
}

@kmalakoff , was ich erstellen und diese dann mit uns teilen (zusammen mit Anwendungsbeispielen). Dadurch werden Ihr Vorschlag und Ihre Begründung hundertmal klarer. Da alle Lebenszykluspunkte bereits über entsprechende Callbacks verfügen, können Sie an jedem Lebenszykluspunkt / Komponentenzustand jede neue Methode einführen. Sie können sogar einen Event-Emitter in Ihre Komponente mischen und es ermöglichen, mehrere Handler für einen Zustandswechsel hinzuzufügen.

@shea256 , ein möglicher Grund dafür, dass componentWillReceiveProps nicht vor dem ersten Rendern ausgelöst wird, ist, dass es zu diesem Zeitpunkt kein this.props . Normalerweise vergleicht man in componentWillReceiveProps this.props[propName] mit newProps[propName] . Wenn die Methode vor dem ersten Rendern ausgelöst wird, müssen Sie auch prüfen, ob this.props . Darüber hinaus ist die gesamte Komponente zu dem Zeitpunkt, an dem sie vor dem ersten Rendern props empfängt, vollständig nicht initialisiert, sie hat nicht einmal state .

@kmalakoff , ich habe zweimal Codebeispiele gepostet, die zeigen, wie man eine React-Komponente so organisiert, dass sie keine setup oder ähnliche Hacks benötigt. Könnten Sie bitte sagen, warum Sie immer noch bestrebt sind, das Verhalten einer React-Komponente zu ändern, anstatt Ihren Code so anzupassen, dass er in React integriert wird? Es wäre toll, wenn Sie nur darauf hinweisen, wo meine Beispiele für Ihren Anwendungsfall ungeeignet sind.

@akinnee-gl , der Grund, keine neue Methode für den einfachen Zugriff auf this.props beim Update einzuführen, ist, dass wir eine solche Methode haben - sie heißt render() . Es wird sogar nach einem Scheck für shouldComponentUpdate() aufgerufen - was normalerweise ein Ort ist, an dem Sie this.props !== newProps oder _.isEqual(this.props, newProps) usw.
Wenn Sie der Meinung sind, dass Sie für einige Einstellungen eine separate Methode haben sollten, warum nicht einfach eine React-Komponente unterklassen und eine folgende render() Methode definieren

this.setup(this.props);
return this._render();

Ich sehe einfach nicht, wie es die Dinge im React-Ökosystem vereinfacht, aber das fordern Sie immer wieder.

@me-andre Die Prämisse dieses Problems ist nicht, dass wir mit der aktuellen API nicht das erreichen können, was wir wollen, oder dass wir die aktuelle API im Clientcode nicht umgehen können. Die Prämisse dieses Problems ist, dass die aktuelle React-API nicht optimal ist und verbessert werden muss ; Wenn Sie beispielsweise Prinzipien entwickeln würden, wie eine optimale API aussehen würde (wie ich es oben versucht habe), würde die aktuelle React-API im mittleren Bereich abschneiden, da sie in einer Reihe von Bereichen suboptimal / mangelhaft ist.

Leider werden durch die Bereitstellung von Möglichkeiten im Client-Code zur Umgehung der React-API nicht die Grundursachen des Problems angegangen, die Debatte weg von den zugrunde liegenden Problemen verlagert und keine Debatte über mögliche Lösungen zur Verbesserung der React-API geführt.

Kurz gesagt, ich habe bereits Workarounds, die für mich funktionieren, da ich eine Reihe von React-Apps in Produktion habe, sodass Best Practices großartig für einen Blog-Post sein könnten, aber sie als Diskussionslinie in dieser Ausgabe zu verwenden, wird uns nur von einem echte Debatte über den wahren Zweck dieser Ausgabe: wie die React-API verbessert werden kann (in dieser Ausgabe beschränkt auf Prop Use Cases und Boilerplate).

React 1.0 sollte die Spitze anstreben, nicht die Mitte. Eine größere Versionserhöhung kann die Abwärtskompatibilität beeinträchtigen, also lassen Sie uns die bestmögliche API suchen, die auf dem basiert, was wir aus all den Jahren der Verwendung der 0.x-Version gelernt haben.

(Zu Ihrer Information: Ich denke, die Leute beschäftigen sich vielleicht nicht so sehr mit Ihren Beispielen, wie Sie hoffen, weil sie nicht hierher kommen, um sich über die aktuelle API zu informieren, sondern weil sie nach Verbesserungen der API suchen / auf Verbesserungen hoffen, z könnte als mit guten Absichten wahrgenommen werden, aber leicht falsch ausgerichtet sein)

Ich denke, die Leute beschäftigen sich möglicherweise nicht so sehr mit Ihren Beispielen, wie Sie es sich erhoffen, weil sie nicht hierher kommen, um sich über die aktuelle API zu informieren, sondern weil sie nach Verbesserungen der API suchen/auf diese hoffen

Ok, Sie kommen mit einem Vorschlag zur API-Verbesserung, zeigen dann aber den Code, der viel zu weit von "Best Practices reagieren" entfernt ist. Manche Dinge scheinen sehr wie schlimmste Praktiken zu sein. Dann sagst du: "Das ist der Grund für einen Wechsel". Ja, das ist der Grund für eine Änderung, aber nicht in der React-Codebase.
Ich zeige Ihnen, wie Sie den Code neu organisieren, damit er gut mit React funktioniert, aber ignorieren Sie einfach die ordnungsgemäße Verwendung und bestehen Sie darauf. Das scheint keine konstruktive Debatte zu sein.

Leider behebt das Bereitstellen von Möglichkeiten im Clientcode zur Umgehung der React-API nicht die Hauptursachen des Problems

Wenn Sie eine Low-Level-API mit einer High-Level-API umschließen, ist dies keine Problemumgehung, sondern eine gängige Praxis. Viele brillante Frameworks folgen dieser Idee.
Was ich immer wieder erzähle, ist, die vorhandene hässliche API mit dem zu verpacken, was Sie verwenden und mit uns teilen möchten. Zusammen mit den Anwendungsbeispielen und Erklärungen, warum es besser wurde, wäre es unglaublich.
Auch hier sehe ich keinen Grund, warum Sie das nicht einfach tun. Denn wenn es sich um ein häufiges Problem handelt, wäre das für viele Menschen eine große Hilfe.

Ich habe eine Reihe von React-Apps in der Produktion, daher könnten Best Practices für einen Blog-Post großartig sein, aber sie als Diskussionslinie in dieser Ausgabe zu verwenden, wird uns nur von einer echten Debatte ablenken

Was Sie normalerweise tun, wenn Sie eine API entwerfen/entwerfen, ist die Vorhersage von Problemen, Hypothesen über Anwendungsfälle usw. Der Grund, warum Leute Hypothesen aufstellen, ist nicht, dass sie versuchen, sich auf der Suche nach dem Ideal von der realen Welt zu abstrahieren. Es fehlt einfach an Erfahrung - Erfahrung kann man nicht "im Voraus" sammeln.

Sie sagen, dass Sie diese Erfahrung haben, echte Probleme gesehen haben und einige Problemumgehungen haben, die Sie teilen können. Genau das kann diese Debatte „real“ und „effektiv“ machen. Das React selbst wurde auf realen Problemen und Herausforderungen aufgebaut - deshalb löst es echte Architekturprobleme und nicht nur "wie schreibt man Hallo Welt in 3 Zeilen".

@me-andre Ich höre dich und deine Argumentation ist klar.

Sie haben Recht, dass mein Argument im Mittelpunkt steht, dass wir, wenn wir auf der Grundlage unserer gemeinsamen Erfahrungen mit der aktuellen React-API bessere Prinzipien aufstellen und die Debatte eröffnen, um nicht-dogmatische Lösungen einzubeziehen, die die API auf grundlegende Weise verändern könnten, können und sollten nutzen Sie die Gelegenheit, die React-API zu verbessern, um sie noch besser zu machen, als sie es heute ist. Lassen Sie uns nicht auf unseren Lorbeeren ausruhen, wenn es Raum für Verbesserungen gibt!

Wie würden Sie die aktuelle React-API in Bezug auf Requisiten bewerten? (sagen wir mit Buchstabennoten: F bis A+), warum, und was würden Sie tun, um es zu verbessern, wenn es weniger als A+ ist?

@me-andre hattest du die möglichkeit dein Ranking und deine Analyse vorzubereiten? Ich bin daran interessiert, zu erfahren, was Ihrer Meinung nach die Stärken, Schwächen und Möglichkeiten der aktuellen API sind.

+1

+1 Bitte

Gibt es einen Workaround? Ich brauche ComponentDidReceiveProps

Ich habe dieses Problem vor über einem Jahr gemacht und benutze React seitdem täglich. Ich glaube nicht mehr, dass es einen Anwendungsfall für ComponentDidReceiveProps gibt, der eine Erweiterung der API rechtfertigt.

@AlexCppns was

@iammerrick , eigentlich ist es in Ordnung, ich habe nur missverstanden, wie ComponentWillReceiveProps verwendet wird.

Ich bin ein paar Mal darauf gestoßen und habe Folgendes getan:

componentWillReceiveProps(nextProps) {
  if (this.props.foo !== nextProps.foo) this.needsUpdate = true;
}
componentDidUpdate() {
  if (this.needsUpdate) {
    this.needsUpdate = false;
    // update the dom
  }
}

Es ist nicht so schlimm.

@brigand , es ist keine Flagge erforderlich - Sie können Requisiten innerhalb von componentDidUpdate() :

componentDidUpdate(prevProps) {
    let needsUpdate = prevProps.foo !== this.props.foo;
    // ...whatever
}

Darüber hinaus könnte Ihre Lösung leicht durch shouldComponentUpdate() , was ein erneutes Rendern verhindern kann.

Oh cool, danke!

@jimfb Ich glaube, ich habe unten einen synchronen Anwendungsfall. Ich denke, ein componetDidReceiveProps wäre perfekt dafür gewesen.

  componentDidMount() {
    this._selectAll()
  }

  componentDidUpdate(prevProps) {
    let shouldUpdateSelected = (prevProps.recordTypeFilter !== this.props.recordTypeFilter) ||
      (prevProps.statusFilter !== this.props.statusFilter) ||
      (prevProps.list !== this.props.list)

    if (shouldUpdateSelected) { this._selectAll() }
  }

  _selectAll() {
    this.setState({ selectedIds: this._getFilteredOrders().map((order) => ( order.id )) })
  }

  _getFilteredOrders() {
    let filteredOrders = this.props.list

    // recordTypeFilter
    let recordTypeFilter = this.props.recordTypeFilter
    filteredOrders = _.filter(filteredOrders, (order) => {
        // somelogic
    })

    // statusFilter
    let statusFilter = this.props.statusFilter
    filteredOrders = _.filter(filteredOrders, (order) => {
        // somelogic
    })

    return filteredOrders
  }

@chanakasan , Ihrem Beispiel fehlt die Methode render() , die sowohl für das Verständnis Ihres Beispiels als auch für den Vorschlag einer besseren Lösung unerlässlich ist.
Zweitens ist Ihr Code mit einer benutzerdefinierten Geschäftslogik verbunden und nicht leicht zu lesen. Zögern Sie nicht, es zu erklären, und werfen Sie nicht einfach ein Copy-Paste in andere.
Ich habe Ihr Beispiel jedoch gelesen und möchte folgende Gedanken teilen:

  1. Dies ist der Anwendungsfall von componentWillReceiveProps , nicht von componentDidUpdate . Wenn Sie zu componentWillReceiveProps wechseln, würde Ihre Komponente doppelt so weniger erneut rendern, während die gleiche Logik beibehalten wird. Nach einem Jahr, seit ich diese Diskussion verlassen habe, sehe ich immer noch keinen Anwendungsfall für componentDidUpdate außer der Reaktion auf DOM-Änderungen.
  2. Viel besser wäre es jedoch, Hooks überhaupt zu vermeiden und die gesamte Logik auf die Methode render() / zu einer zustandslosen Komponente zu migrieren, da this.state.selectedIds eigentlich kein Zustand ist. Es wird rein aus Requisiten berechnet.

Hallo @me-andre, danke, dass du dir die Zeit genommen hast zu antworten. Ich habe die Diskussion auf dieser Seite gelesen und möchte Ihnen für Ihre Teilnahme danken.

Ja, ein componentDidReceiveProps wird nicht benötigt, aber ohne es scheint die Sache mysteriös.
Sie haben your component would re-render twice as less gesagt, wenn ich componentWillReceiveProps . Das ist mir immer noch ein Rätsel.

Ich habe die beiden Dinge, die Sie zuvor vorgeschlagen haben, überlegt und ausprobiert, aber es ist gescheitert.

  1. componentWillReceiveProps funktioniert nicht, weil die _getFilteredOrders() Funktion, die von _selectAll() aufgerufen wird, die newProps benötigt.
  2. Ich konnte mir keine Möglichkeit vorstellen, die selectedIds abzuleiten, ohne sie im Status zu speichern.

Ich habe gerade ein vollständiges Beispiel aus meinem Anwendungsfall erstellt. Ich habe es so leicht wie möglich verständlich gemacht.

Wenn Sie bitte einen Blick darauf werfen und mich in die richtige Richtung weisen könnten. Wenn ich das richtig verstehe, werde ich dieses Beispiel in einem Blogbeitrag teilen, um auch anderen zu helfen.

@chanakasan , komm schon, das sieht aus wie ein Produktionscode. Ich werde nicht alles lesen und Ihnen bei Ihrem Projekt kostenlos helfen.

Ich kann Sie jedoch in die richtige Richtung weisen:

  1. Sowohl componentWillReceiveProps() als auch componentDidUpdate() können auf vorherige und nächste Requisiten zugreifen. Das geht eindeutig aus den offiziellen React-Dokumenten hervor.
  2. Aus dem vollständigen Copypaste Ihres Codes ist jetzt ersichtlich, dass Sie state zum Speichern ausgewählter IDs verwenden, die ein Benutzer umschalten kann. Es ist dann in Ordnung, state zu verwenden, aber componentWillReceiveProps() würde das erneute Rendern doppelt so wenig auslösen. (da sowieso nach componentWillReceiveProps() ein Rendern stattfinden wird, würde setState() nur den Status für das bevorstehende Rendern aktualisieren).
  3. Bitte werfen Sie einen Blick in die Dokumente . Sparen Sie Zeit und respektieren Sie andere.

@me-andre Ich glaube, ich verstehe Ihren Standpunkt zu componentWillReceiveProps mit dieser Zeile in den Dokumenten:

componentWillReceiveProps() wird nicht aufgerufen, wenn Sie nur this.setState() aufrufen

Aber die Einschränkung bei der Verwendung von componentWillReceiveProps ist, dass ich nextProps an Funktionen weitergeben muss.

Ich werde versuchen, deinem Rat zu folgen. Danke, ich weiß es zu schätzen.

Übrigens, es war nicht meine Absicht, dass Sie kostenlos bei meinem Produktionsprojekt helfen :). Es ist ein vollständigeres Beispiel aus meinem vorherigen kurzen Beispiel, um alle Lücken zu meinem Anwendungsfall auszufüllen.

Was ist, wenn wir dies in Verbindung mit shouldComponentUpdate verwenden?
wobei wir den Komponentenstatus nicht aktualisieren oder erneut rendern möchten,
aber wir brauchen this.props, um die neuesten Requisiten zu verwenden, um einige manuelle Skriptarbeiten zu erledigen, nachdem die Requisiten empfangen wurden

Meine Problemumgehung besteht darin, this.props auf die neuen Requisiten zu setzen, bevor die gewünschte Funktion ausgeführt wird

Es wäre wirklich schön, den ComponentDidMount oder einen Haken dafür zu haben. Wieso den? Denn manchmal müssen wir andere Berechnungen durchführen, die nicht vom React-Lebenszyklus abhängen.

Beispiel: Ich habe eine übergeordnete Komponente, deren Größe geändert werden kann. Die untergeordnete Komponente ist dafür verantwortlich, eine OpenLayer-Map zu rendern, die eine Funktion hat, die für die Größenänderung der Map verantwortlich ist. Dies sollte jedoch passieren, nachdem das Kind Requisiten vom Elternteil erhalten und auch andere Berechnungen innerhalb des React-Lebenszyklus festgeschrieben hat.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen