Vue: Warten Sie auf asynchrone Komponentenlebenszyklus-Hooks

Erstellt am 8. Dez. 2017  ·  51Kommentare  ·  Quelle: vuejs/vue

Welches Problem löst diese Funktion?

Wenn ein Benutzer einen Lebenszyklus-Hook implementieren muss, der von asynchronen Vorgängen abhängt, sollte vue die asynchrone Natur des implementierten Hooks respektieren und im vue-Land darauf warten.

Wie sieht die vorgeschlagene API aus?

Die API ändert sich nicht; nur, wie es jetzt funktioniert, indem asynchrone Hooks erwartet werden.

Hilfreichster Kommentar

Dies ist der eigentliche Code, auf den ich gewartet werden möchte:

  beforeMount: async function() {
       this.user = await client.get({type: 'user', id: this.$route.params.id});
    }

Welches Teil der UserPage Komponente wäre.

Alle 51 Kommentare

Also du möchtest

created () {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('created')
            resolve()
        })
    })
},
mounted () {
    console.log('mounted')
}

anzeigen

mounted

?

Wenn Sie eine Funktionsanfrage erstellen, fügen Sie bitte einen realen Anwendungsfall hinzu, damit es sich lohnt, die Anfrage zu implementieren.

Obwohl dies theoretisch eine coole Idee ist, erfordert dies ein grundlegendes Überdenken / Umschreiben der Architektur und kann möglicherweise eine Menge Logik durchbrechen, die auf der synchronen Natur von Lebenszyklus-Hooks beruht. Die Vorteile müssen also erheblich sein, um diese Änderung zu rechtfertigen – andernfalls kann dies nur in Betracht gezogen werden, wenn wir ein vollständiges Upgrade planen, was wahrscheinlich nicht sehr bald erfolgen wird.

Vorerst geschlossen, aber zögern Sie nicht, konkretere Argumente / Anwendungsfälle / Implikationen nachzuverfolgen.

@posva Verstanden – ich entschuldige mich. Mein tatsächlicher Anwendungsfall ist einer, bei dem ich eine UserPage Komponente habe, die ein user_id von den Seitenroutenparametern empfängt (über this.$route.params ) und dann die tatsächlichen Benutzerdaten aus der Datenbank abruft auf dem Server mit einem Befehl wie:
this.user = await client.get({type: 'user', id: this.$route.params.id})
Dabei bezieht sich this.user auf ein user Feld im data Teil der UserPage Komponente.

Idealerweise möchte ich, dass diese Codezeile ausgeführt wird, nachdem die Komponente erstellt wurde (damit this.$route.params verfügbar ist), aber bevor die Komponente tatsächlich gemountet wird, damit ich in meiner Vorlage sicher user -Interpolationen, ohne Fehler über undefinierte Werte zu erhalten.

@yyx990803
Ich bin hier vielleicht ein Neuling, aber sollte nicht die einzige Änderung darin bestehen, das Schlüsselwort await vor dem Aufruf von Lifecycle-Hooks wie mounted usw. im Vue-Land hinzuzufügen?

Dies ist der eigentliche Code, auf den ich gewartet werden möchte:

  beforeMount: async function() {
       this.user = await client.get({type: 'user', id: this.$route.params.id});
    }

Welches Teil der UserPage Komponente wäre.

Kein Problem! Ich habe mir diesen Anwendungsfall vorgestellt. Es ist besser, es wie in den vue-router-Dokumenten beschrieben zu handhaben, da es verschiedene Möglichkeiten zum Anzeigen des Ladezustands bietet. Sie können bereits warten, bis die Daten da sind, bevor Sie die Komponente rendern.

Okay das macht Sinn. Was aber, wenn ich eine Benutzerkomponente habe, die eine abgespeckte Version der Benutzerseite ist (z ist hier nicht beteiligt und id wird als Eigenschaft an die Komponente übergeben.

Wenn man hier das Gesamtbild betrachtet, können Funktionen in JavaScript jetzt entweder synchron oder asynchron sein, und dass Lifecycle-Hooks Funktionen sind und wie wir sie als Funktionen betrachten, sollten Asynchronität unterstützen (wie durch meinen Anwendungsfall und die intuitive "Reichweite" gezeigt) für den Ansatz, den ich hier verwende).

Sie haben viele Möglichkeiten, dies zu tun. Die einfachste Möglichkeit besteht darin, eine Variable zu verwenden, die als null beginnt, die Daten abzurufen und zu setzen, wobei die eigentliche Komponente umgeschaltet wird (wegen eines v-if). Eine exotischere Version wäre eine Funktion, die die Komponente auflöst und ein <component :is="myDynamicComp"/> 😄
Aber bitte nimm das Thema nicht in eine Frage nutze dafür das Forum oder die Zwietracht

Nein, ich möchte wirklich keine Hilfe mit dem Code! Tatsächlich habe ich bereits Workarounds implementiert, die Ihren Vorschlägen sehr ähnlich sind. Was ich damit sagen möchte, ist, dass es viel intuitiver ist, nur die asynchronen JS-Funktionen zu verwenden.

Was mir nicht klar war, ist, dass asynchroner und synchroner Code grundsätzlich unterschiedlich sind, sodass synchroner Code nicht gezwungen werden kann, asynchronen Code einzuhalten, ohne sich selbst grundlegend in asynchronen Code zu ändern. yyx990803 sah es sofort, aber ich brauchte einige Zeit, um seinen Kommentar vollständig zu verstehen. Vielen Dank für Ihre Zeit, Jungs und Entschuldigung, wenn es irgendwo ein Missverständnis meinerseits gab.

Ich habe hier einen Anwendungsfall und möchte einen Vorschlag und eine Problemumgehungsmethode erhalten.

MainPage.vue ist mein Hauptcontainer. Ich rufe Ajax "/init" bei beforeCreate auf, um Benutzerinformationen abzurufen, und verbinde mich dann mit Vuex.store.
Content.vue ist das Kind in MainPage.vue . Ich möchte verschiedene API-Aufrufe in der Phase mounted je nach Benutzerrolle aufrufen, die von Vuex.store stammen.

Wenn der Lifecycle-Aufruf im async/await-Flow wäre, würde er der Reihenfolge folgen
Parent beforeCreate -> Parent erstellen -> Child beforeCreate -> Child erstellen -> Child eingehängt .... (Wenn ich den Lebenszyklus von Komponenten richtig verstehe).

Aber derzeit kann ich keine Benutzerinformationen unter Content.vue abrufen. Wie kann ich jetzt Abhilfe schaffen?
Ich möchte die API "/init" in MainPage.vue belassen, da sie auf vielen Seiten verwendet wird (Container in Vue-Router).

Frage zu Stackoverflow gepostet

Vielen Dank

ein hackischer Workaround für das, was sich lohnt:

{
  created: function(){
    this.waitData = asyncCall();
  },
  mounted: function(){
    this.waitData.then(function(data) { ... })
  }
}


Eine mögliche "flachere" Lösung:

{
    async created () {
        let createdResolve = null
        let createdReject = null
        this.createdPromise = new Promise(function(resolve, reject){
            createdResolve = resolve
            createdReject = reject
        })
        await asyncCall1()
        await asyncCall2()
        ...
        createdResolve(someResult)
    }
    async mounted () {
        let result = await this.createdPromise
        ...
    }
    data () {
        return {
            createdPromise: null
        }
    }
}

Ist das noch kein Ding?

data() {
 ...
},
async created() {
  const something = await exampleMethod();
  console.log(something);
}

Funktioniert bei mir (wie @fifman erwähnt).

@breadadams Ja, natürlich. Die Funktionen _innerhalb_ der Methode created werden erwartet - die Funktion created oder mounted selbst jedoch nicht.

Die Vue-Instanz ruft also created und sofort mounted bevor einer der lang andauernden Prozesse in created beendet ist

Ah , mein schlechter @darren-dev - anderer Anwendungsfall auf meiner Seite, aber ich sehe das Problem jetzt 😅 danke für die Klärung.

@breadadams Überhaupt kein Problem - wir sind alle für unsere eigenen Fälle da, froh, dass ich das klären konnte!

Async-Lifecycle-Hook kann eine gute Implementierung in der nächsten Hauptversion sein

Mir scheint, dass das Zulassen einer asynchronen Unterstützung für die Lebenszyklusmethoden standardmäßig schlechte UX-Praktiken fördert. Wie? Async-Funktionen werden für Anfragen verwendet, die nicht sofort abgeschlossen werden können (zB lang andauernde oder Netzwerkanfragen). Wenn Sie Vue zwingen, die Erstellung oder Bereitstellung oder eine der anderen Lebenszyklusmethoden zu verzögern, um auf Ihre Netzwerkanforderung oder einen lang andauernden asynchronen Prozess zu warten, wirkt sich dies auf den Benutzer spürbar aus. Stellen Sie sich vor, ein Benutzer kommt auf Ihre Site und muss dann 4 Sekunden mit leerem Bildschirm warten, während die Komponente darauf wartet, dass die fleckige Mobilfunkverbindung des Benutzers Ihre Netzwerkanforderung beendet. Und dies wirkt sich nicht nur negativ auf den Benutzer aus, sondern Sie opfern auch Ihre Kontrolle über die Situation - Sie können als Entwickler nichts tun, um den Benutzern die Ladezeit zu verkürzen oder bestimmte oder unbestimmte Fortschrittsindikatoren anzuzeigen. Wenn Sie also diese Fähigkeit in Vue einbauen, machen Sie das Web nicht zu einem besseren Ort; Sie ermöglichen schlechte Praktiken.

Es ist viel besser, den asynchronen Fall von Anfang an zu planen und zu entwerfen: Starten Sie Ihren asynchronen Prozess in created oder mounted oder wo auch immer, und machen Sie dann Ihre Komponente mit einer Skelettstruktur oder im schlimmsten Fall ein Spinner, während Sie darauf warten, dass Ihre API die Berechtigungen des Benutzers zurückgibt. Viel bessere UX und Sie verlieren keine Kontrolle. Und Vue muss keinen Code hinzufügen, um mit asynchronen Lebenszyklusfunktionen umzugehen, wodurch das Bundle kleiner bleibt. Gewinn gewinnen.

@seanfisher Sie

Haftungsausschluss : Das Folgende wurde im Hinblick auf die Seitengenerierung geschrieben. Es gibt definitiv gültige Anwendungsfälle, in denen mein Argument ungültig ist.


Das Diktieren der Entwurfsmuster eines Entwicklers sollte jedoch nicht dem Framework überlassen werden, das Sie verwenden. Mein Argument ist, dass, wenn Sie nicht darauf warten, dass eine Phase abgeschlossen ist, warum dann verschiedene Phasen haben? Warum eine erstellte, dann montierte Bühne? Wenn im Grunde alles auf einmal passiert, ist es in Ordnung, die erstellte Bühne vollständig zu ignorieren.

Buchstäblich war das einzige Mal, dass ich (seit den frühen Vue) jemals erstellt habe, als ich etwas injizieren musste, auf das sich Vue verlassen musste - es hatte nichts mit der Einrichtung oder dem Layout meiner Seite zu tun. Ich musste jedoch warten, bis (kurze) asynchrone Aufgaben ausgeführt wurden, die viel besser wären, _bevor_ die Seite gerendert wurde (z. B. das Einhaken in die Authentifizierungsmethoden von Firebase). Wenn Sie dies in create haben und dann darauf warten, dass es abgeschlossen ist, bevor Sie es mounten, würde dies die Notwendigkeit hackiger Workarounds vollständig reduzieren.

Denken Sie daran, mein Argument ist, dass Vue mir nicht sagen sollte, dass ich mich falsch entwickle. Es sollte nur die gewünschte Funktionalität bieten.

Das Diktieren der Entwurfsmuster eines Entwicklers sollte jedoch nicht dem Framework überlassen werden, das Sie verwenden.

Äh....Frameworks werden gebaut, um den Entwickler gezielt in bestimmte Designmuster und -praktiken einzuschränken oder zu leiten oder "einzurahmen". Das ist ihr Hauptzweck. Jedes gute Framework bietet eine intelligente API, die eine klare und offensichtliche Möglichkeit bietet, mit dem Framework zu arbeiten, aber auch einschränkend ist.

Ja, es ist paradox, dass ein Framework gewisse Fähigkeiten bietet, den Entwickler aber gleichzeitig auch auf bestimmte Designpraktiken einschränkt. Genau hier kann Meinungsbildung innerhalb von Frameworks entweder helfen oder schaden. Es ist schwer, die richtige Balance zu finden, und ich denke, Vue oder besser gesagt Evan und das Vue-Entwicklerteam haben großartige Arbeit geleistet und machen diese Urteile.

Scott

Ich werde nie argumentieren, dass ein gut gestaltetes Framework mit dem gleichen Entwurfsmuster erweitert werden sollte, aber mein Argument ist, dass das Framework es nicht diktieren kann. Sie haben Recht, aber ich sage, egal wie gut das Framework ist, der Endentwickler sollte immer noch offen sein, zu tun, was er wollte.

Aber Sie haben das _tatsächliche_ Argument, die erstellten und gemounteten Ereignisse asynchron zu machen, nicht berührt - Sie haben nur Ihre Meinung (die nicht falsch ist) meiner Meinung hinzugefügt, was im Allgemeinen zu einer großen Entgleisung führt.

Ich werde nie argumentieren, dass ein gut gestaltetes Framework mit dem gleichen Entwurfsmuster erweitert werden sollte, aber mein Argument ist, dass das Framework es nicht diktieren kann.

Sorry, aber das macht für mich keinen Sinn. Bitte zeigen Sie mir ein Framework, das nicht vorschreibt, wie es erweitert werden soll.

Ich dachte, mein Spruch "Evan und Co, die gute Urteilskraft fällen" würde meine Meinung zeigen. Aber um es klarer zu sagen. Die gemounteten und erstellten Lifecycle-Hooks müssen nicht asynchron arbeiten, oder besser gesagt, die Tatsache, dass sie synchron arbeiten, hilft beim Nachdenken über die Anwendungslogik. Jedes "Warten" muss ohnehin in der Benutzeroberfläche berücksichtigt werden und asynchroner Code kann weiterhin in jedem Hook ausgeführt werden. Wir können uns darüber streiten, dass jetzt die Vormount- und Mount-Haken notwendig sind. Aber es könnte ein oder zwei Dinge geben, die Sie zum Beispiel in mount benötigen, auf die Sie in created noch nicht zugreifen können, wie die kompilierte Render-Funktion.

Scott

Wenn Vue auf die eine oder andere Weise eine Meinung zu asynchronen Lebenszyklus-Hooks hat, sollte dies keine Frage von Spekulationen sein. Es besteht kein Grund zu spekulieren, wann die Standards, APIs, Leitfäden und Best Practices, die Vue annimmt, bereitstellt oder empfiehlt, für alle zugänglich sind.

In Evans ursprünglicher Antwort sind asynchrone Lebenszyklus-Hooks nicht in der Standard-API enthalten, nicht weil dies unbedingt eine schlechte Idee ist, sondern weil die Vorteile nicht erheblich genug sind, um die Implementierungskosten zu rechtfertigen.

Für die Meinung, dass es eine schlechte Praxis ist, den Benutzer auf einen asynchronen created oder einen anderen Lebenszyklus-Hook warten zu lassen, ohne einen Indikator dafür zu haben, dass etwas passiert, kann man argumentieren, dass Vue, der asynchrone Hooks unterstützt hat, jetzt vielleicht bietet etwas, das als "Phasenschablonen" bezeichnet werden könnte und das auch das Problem lösen würde (und das leicht zu implementieren sein könnte).

Für die Meinung, dass es eine schlechte Praxis ist, den Benutzer auf einen asynchron erstellten oder anderen Lebenszyklus-Hook warten zu lassen, ohne dass ein Indikator dafür vorliegt, dass etwas passiert,

Ist das wirklich überhaupt ein Problem?

Scott

Hier ist das Problem, das ich habe - und vielleicht kann mir jemand vorschlagen, wie ich dies tun sollte, da dies problematisch erscheint.

Unsere Vue-Anwendung (eher groß) verwendet Vuex ausgiebig. In einigen unserer Vue-Komponenten im create()-Lebenszyklus setzen wir über store.dispatch() einige Items im Store (offensichtlich). Wie mir jedoch aufgefallen ist, gibt store.dispatch() IMMER ein Versprechen zurück.. selbst wenn die zugrunde liegende Logik und Funktion NICHT asynchron ist. Also habe ich async erstellt () {await store.dispatch('foo/action')} eingefügt, aber wie bereits erwähnt, schlägt dies tatsächlich fehl.

Ich verwende auch Typescript und es beschwert sich ziemlich bitter, wenn ich nicht auf / warte. Dann ruft store.dispatch() auf.

Was ist also der beste Weg, Vuex store.dispatch() in einem Lebenszyklus zu verwenden, wenn wir sie nicht asynchronisieren können?

Danke schön!!

Bei allen anderen Diskussionen über die spezifischen Meinungen von vue und ob Frameworks Meinungen beiseite schieben sollten, könnte es von Vorteil sein, dieses Verhalten klarer zu dokumentieren.

Ich schaue mir die "flachere" Lösung von mounted() zurückkehrt. In dieser Lösung sind sowohl created() als auch mounted() asynchron, sodass Vue jeden von ihnen aufruft und sie mehr oder weniger sofort zurückkehren, wobei die asynchronen Dinge im Hintergrund ablaufen. Tatsächlich bin ich mir nicht sicher, wie das besser ist, als einfach die createdPromise abzuschaffen und einfach die gesamte asynchrone Arbeit entweder in created() oder mounted() , wie:

async mounted() {
  let response = await fetch(my_url)
  let data = await response.text()
  my_data_member = data
}

Auf jeden Fall wird my_data_member "später" ausgefüllt, wenn der XHR abgeschlossen ist, lange nachdem mounted() sein Versprechen zurückgegeben hat, oder?

Sie können auch versuchen, v-if für die Root-Komponente <div id="app"/> und sie auszulösen, wenn das Laden der Daten abgeschlossen ist. Ich verwende es zum Beispiel für das Aktualisierungstoken.

Dies ist eine coole Funktion und hat viele Anwendungsfälle. Für meinen Anwendungsfall muss ich vor dem eigentlichen Rendern der Komponente bestimmte API-Eigenschaften laden. Ich glaube jedoch nicht, dass Async in Lifecycle-Hooks eine ideale Lösung ist.

Derzeit erwähnen alle hier ein perfektes Szenario, in dem die Async-Funktionen reibungslos laufen. Aber sagen wir zB, wenn die Verbindung des Benutzers langsam oder verzögert ist und wir warten, bis die Komponente nach der Antwort einer API gemountet wird, dann wird der gesamte Lebenszyklus der Komponente verteilt. Wir können dem Benutzer keine Ladeinformationen anzeigen. Oder noch schlimmer, wenn die API eine Zeitüberschreitung oder einen Fehler zurückgibt, bleibt die Anwendung ohne Mounten hängen.

Obwohl dies eine coole Funktion ist, würde ich vorschlagen, dass sie von der Anwendung und nicht vom Framework verarbeitet wird, da die Domänenlogikimplementierung mehr Einblick in die zugrunde liegende Logik hat als das Framework, wodurch weniger Nebenwirkungen verursacht werden.

+1 für diese Funktion.
Ich habe ein Mixin, das von verschiedenen Komponenten verwendet wird, das Mixin holt Daten aus einer Datenbank im gemounteten Hook.
Die Komponenten müssen mit den vom Mixin geholten Daten auch im montierten Hook arbeiten.
So wie es jetzt ist, musste ich einen Callback implementieren, der aufgerufen wird, wenn das Mixin mit dem Laden der Daten fertig ist, und den gemounteten Hook in der Komponente wegwerfen.
Es funktioniert, wäre aber schöner, wenn der montierte Hook verspricht, was er verspricht.

@cederron aus v-if , um einen Ladeindikator anzuzeigen, während die Daten geladen werden. Wenn die Daten angezeigt werden, können Sie die Komponente anzeigen, und wenn sie erstellt wird, enthält sie alle erforderlichen Daten.

Verhindert, dass die Komponente zwei unterschiedliche, nicht zusammenhängende Zustände darstellt („keine Daten geladen, wartend“ und „Daten wurden geladen, Sie können sie bearbeiten“)

Wenn Sie die Logik an mehreren Stellen wiederverwenden müssen, möglicherweise sogar die Download-Logik nach Vuex verschieben, ist das irgendwie sinnvoll, da das Herunterladen von Daten in einer Vuex-Aktion und nicht in einer Komponente erfolgen würde.

@ReinisV Ich glaube, ich habe meinen Fall zu stark vereinfacht, die Komponente erstellt neue Daten aus den Daten, die vom Mixin-Mount-Hook abgerufen wurden, und die Komponentenansicht ist an diese neuen Daten gebunden.
Das Mixin muss also Daten aus der Datenbank holen > die Komponente erstellt daraus Daten > jetzt wird die Komponente angezeigt

AFAIK das geht nicht:

export const MyMixin = {
    data: function () {
        return {
            dbData: null
        }
    },
   mounted:  async function () {
      this.dbData = await asyncFetchDataFromDB()
   }
}


export const MyComponent = {
    mixins: [MyMixin],
    data: function () {
        return {
            newData: null
        }
    },
   mounted:  function () {
      this.newData = handleDBData(this.dbData)
   }
}

dbData wird im Komponenten-Mount-Hook null sein.

Derzeit führe ich einen Callback aus, wenn das Mixin die Daten abruft, aber es wäre schöner, die Mount-Funktion einfach asynchron zu machen.

Zu vuex kann ich nicht viel sagen, da ich es nicht benutze

Ich möchte wirklich wiederholen, was @seanfisher hier erwähnt hat. Das Warten auf Komponenten, die als asynchron markiert wurden, verursacht nicht nur Probleme für die Benutzer, sondern das Muster der Verwendung von async/await zum Starten der Datensuche ist überall vorhanden. Es würde eine explizite Konvertierung des Codes in diesen Lebenszyklus-Hooks in unerwartete Versprechen erzwingen, um das Blockieren von vue explizit zu vermeiden. In einigen Fällen könnte es gut sein, und wenn eine Funktion eingeführt würde, müsste ich vorschlagen, zwei Lebenszyklen gleichzeitig auszuführen, den aktuellen, der die Ausführung von Komponenten-Hooks behandelt, und einen, der diese Ausführungen für globale Rückrufe erwartet.

Aber ich wäre wirklich enttäuscht, jeden meiner Lebenszyklus-Hooks buchstäblich neu zu schreiben, um das Blockieren von Vue zu vermeiden. async/await ist viel sauberer, also verwenden wir keine Versprechungen. Wenn Sie dies auf nicht abwärtskompatible Weise ändern, wird die Erfolgsgrube (unerwarteter Komponentenlebenszyklus) in eine Fehlergrube umgewandelt.

Es ist viel besser, den asynchronen Fall von Anfang an zu planen und zu entwerfen: Starten Sie Ihren asynchronen Prozess in created oder mounted oder wo auch immer, und machen Sie dann Ihre Komponente mit einer Skelettstruktur oder im schlimmsten Fall ein Spinner, während Sie darauf warten, dass Ihre API die Berechtigungen des Benutzers zurückgibt. Viel bessere UX und Sie verlieren keine Kontrolle. Und Vue muss keinen Code hinzufügen, um mit asynchronen Lebenszyklusfunktionen umzugehen, wodurch das Bundle kleiner bleibt. Gewinn gewinnen.

@seanfisher Danke, das ist super hilfreich!

Warum nicht stattdessen eine asynchrone Komponente verwenden, die nur gerendert wird, wenn asynchrone Aufrufe zurückgegeben wurden?
mehr Infos zur API hier
https://vuejs.org/v2/guide/components-dynamic-async.html#Async -Komponenten

new Vue({
  components: {
    root: () => ({ // Aync component
      // The component to load (should be a Promise)
      component: new Promise(async function (resolve) {
        await FetchMyVariables()
        resolve(MyComponent) // MyComponent will be rendered only when FetchMyVariables has returned
      }),
      // A component to use while the async component is loading
      loading: { render: (h) => h('div', 'loading') }, 
    })
  },
  render: h => h('root')
})

Während die meisten dieser Lösungen gut erscheinen, denke ich, dass dies eines der wichtigsten fehlenden Teile von Vue ist, die es so intuitiv machen. Ich denke, Vue 3 muss dies implementieren, da wir an einem Punkt angelangt sind, an dem die Verwendung von async-Await jetzt alltäglich ist. SO BITTE @yyx990803 Du, lass es uns in Vue 3 haben. PLEEEEEEEASE. Die gesamte VUE-Architektur wurde ohne Annahmen für diese Fälle erstellt und die meisten Dinge, die die Leute hier posten, sind nur Workarounds und hackisch. Ich denke, Hooks sollten eigentlich asynchrone Funktionen respektieren und auch Rückgabewerte erwarten, die dann an die nächste Hook-Funktion weitergegeben werden.

Ich werde meinen Code umgestalten, da dies nicht honoriert wird, aber hässlicher Code wird herauskommen, da es ein Hack wäre.

Mir scheint, dass das Zulassen einer asynchronen Unterstützung für die Lebenszyklusmethoden standardmäßig schlechte UX-Praktiken fördert. Wie? Async-Funktionen werden für Anfragen verwendet, die nicht sofort abgeschlossen werden können (zB lang andauernde oder Netzwerkanfragen). Wenn Sie Vue zwingen, die Erstellung oder Bereitstellung oder eine der anderen Lebenszyklusmethoden zu verzögern, um auf Ihre Netzwerkanforderung oder einen lang andauernden asynchronen Prozess zu warten, wirkt sich dies auf den Benutzer spürbar aus. Stellen Sie sich vor, ein Benutzer kommt auf Ihre Site und muss dann 4 Sekunden mit leerem Bildschirm warten, während die Komponente darauf wartet, dass die fleckige Mobilfunkverbindung des Benutzers Ihre Netzwerkanforderung beendet. Und dies wirkt sich nicht nur negativ auf den Benutzer aus, sondern Sie opfern auch Ihre Kontrolle über die Situation - Sie können als Entwickler nichts tun, um den Benutzern die Ladezeit zu verkürzen oder bestimmte oder unbestimmte Fortschrittsindikatoren anzuzeigen. Wenn Sie also diese Fähigkeit in Vue einbauen, machen Sie das Web nicht zu einem besseren Ort; Sie ermöglichen schlechte Praktiken.

Es ist viel besser, den asynchronen Fall von Anfang an zu planen und zu entwerfen: Starten Sie Ihren asynchronen Prozess in created oder mounted oder wo auch immer, und machen Sie dann Ihre Komponente mit einer Skelettstruktur oder im schlimmsten Fall ein Spinner, während Sie darauf warten, dass Ihre API die Berechtigungen des Benutzers zurückgibt. Viel bessere UX und Sie verlieren keine Kontrolle. Und Vue muss keinen Code hinzufügen, um mit asynchronen Lebenszyklusfunktionen umzugehen, wodurch das Bundle kleiner bleibt. Gewinn gewinnen.

Eine Meinung von Tausenden. Nur weil Sie sich nicht vorstellen können, dass ein verzögertes Komponenten-Rendering mit einer positiven Benutzererfahrung einhergehen kann, heißt das nicht, dass es nicht existiert.

Wenn ein Framework gegen den Entwickler kämpft, wird der Entwickler ein anderes Framework finden.

@robob4him

Eine Meinung von Tausenden. Nur weil Sie sich nicht vorstellen können, dass ein verzögertes Komponenten-Rendering mit einer positiven Benutzererfahrung einhergehen kann, heißt das nicht, dass es nicht existiert.

Wenn ein Framework gegen den Entwickler kämpft, wird der Entwickler ein anderes Framework finden

Sie haben absolut Recht, aber nichts, was Sie hier geteilt haben, ist ein gültiges Argument, um das Problem auf die eine oder andere Weise zu lösen. Sie haben eine Panikmache eingeführt, um die Community zu zwingen, ein Feature zu entwickeln. Keine konstruktive Fortsetzung des Gesprächs.

@wparad , es ist absolut eine

Die Hälfte der Funktionen von buchstäblich jedem Framework/jeder Sprache sind für einen Entwickler gefährlich; öffentliche Methoden können erweitert werden, Vue fördert den Zugriff auf das Element ($el) usw. Frameworks bieten diese Dinge, weil der Entwickler am Ende des Tages seine Arbeit erledigen muss.

Diese Funktionsanfrage ist ein Jahr alt. Die Leute sollten verstehen, dass der Grund nicht darin liegt, dass dies zu schlechten Praktiken führen würde, noch sollten sie eine verzögerte Wiedergabe als schlechte Praxis ansehen.

Ich muss requirejs mit vue verwenden. Nicht, dass ich requirejs mag, sondern weil ich vue mit einem Open-Source-LMS verwenden möchte, das alle Module als AMD-Module enthält. Es wäre toll, wenn ich alle Bibliotheken, die ich benötige, in den beforeCreate-Hook laden könnte. Die Alternative für mich ist im Moment, sie außerhalb von vue zu laden und sie dann weiterzugeben, was unordentlicher ist.

Mir scheint, dass das Zulassen einer asynchronen Unterstützung für die Lebenszyklusmethoden standardmäßig schlechte UX-Praktiken fördert. Wie? Async-Funktionen werden für Anfragen verwendet, die nicht sofort abgeschlossen werden können (zB lang andauernde oder Netzwerkanfragen). Wenn Sie Vue zwingen, die Erstellung oder Bereitstellung oder eine der anderen Lebenszyklusmethoden zu verzögern, um auf Ihre Netzwerkanforderung oder einen lang andauernden asynchronen Prozess zu warten, wirkt sich dies auf den Benutzer spürbar aus. Stellen Sie sich vor, ein Benutzer kommt auf Ihre Site und muss dann 4 Sekunden mit leerem Bildschirm warten, während die Komponente darauf wartet, dass die fleckige Mobilfunkverbindung des Benutzers Ihre Netzwerkanforderung beendet. Und dies wirkt sich nicht nur negativ auf den Benutzer aus, sondern Sie opfern auch Ihre Kontrolle über die Situation - Sie können als Entwickler nichts tun, um den Benutzern die Ladezeit zu verkürzen oder bestimmte oder unbestimmte Fortschrittsindikatoren anzuzeigen. Wenn Sie also diese Fähigkeit in Vue einbauen, machen Sie das Web nicht zu einem besseren Ort; Sie ermöglichen schlechte Praktiken.

Es ist viel besser, den asynchronen Fall von Anfang an zu planen und zu entwerfen: Starten Sie Ihren asynchronen Prozess in created oder mounted oder wo auch immer, und machen Sie dann Ihre Komponente mit einer Skelettstruktur oder im schlimmsten Fall ein Spinner, während Sie darauf warten, dass Ihre API die Berechtigungen des Benutzers zurückgibt. Viel bessere UX und Sie verlieren keine Kontrolle. Und Vue muss keinen Code hinzufügen, um mit asynchronen Lebenszyklusfunktionen umzugehen, wodurch das Bundle kleiner bleibt. Gewinn gewinnen.

Was Sie sagen, ist, dass das Hinzufügen von v-if/v-clock/v-show Features schlechte Praktiken fördert, sodass wir das Framework besser narrensicher machen, indem wir diese Features entfernen. Verwenden Sie dann einen komplizierten Ansatz, um dasselbe zu tun, damit Vue kleiner ist, um diese 3 Direktiven nicht zu setzen. 1. Entwickler sind nicht dumm. 2. Die Narrensicherheit des Frameworks wiederum schränkt seine Verwendbarkeit ein, da Sie einschränken, was auf der Grundlage scheinbarer "Dummköpfe" getan werden kann. Warum sollte man v-if für seine gesamte Website eingeben, um sie durch asynchrone Vorgänge zu blockieren und den gesamten Bildschirm leer zu lassen?

Ich denke, Sie ignorieren die Tatsache, dass die meisten Anwendungsfälle möglicherweise nicht einmal eine leere Seite haben. Sie werden nicht ohne Grund Komponenten genannt . Fälle, in denen ich dies persönlich verwenden möchte, sind, wenn etwas bereits auf dem Bildschirm etwas anderes tut. Dies kann beispielsweise eine Komponente sein, die von einem v-if blockiert und ausgelöst wird, wenn sich etwas ändert. Beim erstmaligen Rendern müssen jedoch async functions usw. beim Booten der Komponente berücksichtigt werden. Ich habe die gesamte Vue-Dokumentation durchsucht und danach gesucht und es schließlich mit einem sehr nicht so schönen Workaround wie den obigen Hacking-Beispielen getan.

Was mich beunruhigt ist, dass jemand/sogar später ich den Code pflege. Es ist wie die Hölle des Promise-Rückrufs gegen Async ... Warten Sie.

Tatsächlich sehe ich, dass es die Flexibilität und Kontrollierbarkeit des Frameworks auf eine einfach zu verfolgende Weise verbessert. Schau dir einfach die Hacks oben an, um zu sehen, was ich meine. Entwickler tun all dies, um beispielsweise die Lücke einer einfachen async mounted () { await... } Anweisung zu füllen. Wenn Sie diese Funktionen nicht verwenden möchten, definieren Sie die Funktionen einfach nicht als async oder verwenden Sie überhaupt nicht await .

Tatsächlich wird jemand, der tatsächlich einen async mounted Lifecycle-Hook verwendet, höchstwahrscheinlich verstehen, was er tut und warum er es tun wird, und wird höchstwahrscheinlich NICHT die schlechten Praktiken anwenden, über die Sie sich Sorgen machen.

@emahuni , ich glaube nicht, dass irgendjemand der Erwartung widersprechen würde, die Sie teilen, aber ich denke, es gibt eine Nuance, die async mounted oder async created verzögert das Rendern der Komponente. Was machen die Eltern in diesem Fall? Macht es:

  • auch blockieren
  • Nehmen Sie an, dass die Komponente entfernt werden soll, das DOM v-if bis das Laden abgeschlossen ist
  • Nehmen Sie an, dass die Komponente bis zum Abschluss des Ladens ausgeblendet werden soll
  • Ein temporäres Element an seiner Stelle anzeigen?

Ich stimme zwar zu, dass die Erwartungen an eine dynamisch geladene Komponente konsistent sind, aber das Verhalten für das übergeordnete Element ist meiner Meinung nach nicht so. In diesen Fällen würde IMO die Implementierung des Kindes dem Elternteil offenlegen und den Elternteil zwingen, herauszufinden, was mit dieser dynamischen Komponente zu tun ist. Stattdessen sollte es dem Kind überlassen sein, wie die Daten geladen werden und der Zustand der untergeordneten Komponente. Wenn es asynchron geladen wird, muss Vue irgendwie erklärt werden, was an seiner Stelle gerendert (oder nicht gerendert) werden soll. Der beste Weg, damit umzugehen, ist, wie das Framework bereits funktioniert, anstatt eine neue Komplexität einzuführen.

Außerdem verfolge ich deine Argumentation nicht ganz:

Was Sie sagen, ist, als würde das Hinzufügen von v-if/v-clock/v-show-Funktionen schlechte Praktiken fördern, sodass wir das Framework besser narrensicher machen, indem wir diese Funktionen entfernen

In diesem Fall können wir zwar deutlich sehen, dass die Einführung asynchroner Komponenten, die auf das Mounten warten oder erstellt werden, zu schlechten Praktiken führt, aber es ist nicht klar, ob dies der Fall ist. Zweitens stellt sich die Frage, selbst wenn diese schlechte Praktiken verursachen, sollten wir uns dafür entscheiden, sie zu beheben , anstatt sie als Rechtfertigung für die Schaffung neuer schlechter Praktiken zu verwenden. Wenn Sie von schlechten Praktiken wissen, die von v-if usw... für eine andere Diskussion.

@emahuni , ich glaube nicht, dass irgendjemand der Erwartung widersprechen würde, die Sie teilen, aber ich denke, es gibt eine Nuance, die async mounted oder async created verzögert das Rendern der Komponente. Was machen die Eltern in diesem Fall? Macht es:

  • auch blockieren

Die Eltern können weitermachen und rendern, ohne auf das Kind zu warten, warum sollte es das tun? Es kann direkt updated ausführen, sobald das Kind gerendert hat.

  • Nehmen Sie an, dass die Komponente entfernt werden soll das DOM v-if bis das Laden abgeschlossen ist

Ich bin mir nicht sicher, ob ich das verstehe ... aber die Antwort ist nein, wir gehen nicht davon aus, dass es entfernt wird, es muss nur während des Mountens etwas tun, das während dieser Zeit blockiert werden muss. Es gibt viele Anwendungsfälle, die oben dafür gelesen wurden.

  • Nehmen Sie an, dass die Komponente bis zum Abschluss des Ladens ausgeblendet werden soll

Dies hängt vom Entwickler ab, warum er den gemounteten oder einen anderen Hook asynchronisiert.

  • Ein temporäres Element an seiner Stelle anzeigen?

Das mag überhaupt nicht der Fall sein. Auch hier hängt es mit den Entwicklern ab, was sie erreichen wollen. Der Punkt ist, nichts sollte gerade ummantelt sein. Als zum Beispiel v-if entworfen wurde, lag das nicht daran, dass man sich ausmalte, warum jemand das Rendering einer Komponente jedes Mal blockieren möchte und was sie stattdessen platzieren und es narrensicher machten. Es gibt viele Dinge, die mit v-if von Entwicklerdesign schief gehen können. Sie sollten sich keine Sorgen machen, was während dieser Zeit auf dem Bildschirm zu sehen ist, das ist nicht Sache des Frameworks.

Ich stimme zwar zu, dass die Erwartungen an eine dynamisch geladene Komponente konsistent sind, aber das Verhalten für das übergeordnete Element ist meiner Meinung nach nicht so. In diesen Fällen würde IMO die Implementierung des Kindes dem Elternteil offenlegen und den Elternteil zwingen, herauszufinden, was mit dieser dynamischen Komponente zu tun ist. Stattdessen sollte es dem Kind überlassen sein, wie die Daten geladen werden und der Zustand der untergeordneten Komponente. Wenn es asynchron geladen wird, muss Vue irgendwie erklärt werden, was an seiner Stelle gerendert (oder nicht gerendert) werden soll. Der beste Weg, damit umzugehen, ist, wie das Framework bereits funktioniert, anstatt eine neue Komplexität einzuführen.

Zu Ihrer Information: Sie stimmen zu, dass dies implementiert werden muss, jedoch werden dadurch diese Komplexitäten eingeführt, über die Sie weinen, und er hat das Gefühl, dass dies später erfolgen kann, wenn Breaking Changes eingeführt werden, anstatt in Vue 3. Der Punkt ist, dass er es für notwendig hält .

Außerdem verfolge ich deine Argumentation nicht ganz:

Was Sie sagen, ist, als würde das Hinzufügen von v-if/v-clock/v-show-Funktionen schlechte Praktiken fördern, sodass wir das Framework besser narrensicher machen, indem wir diese Funktionen entfernen

In diesem Fall können wir zwar deutlich sehen, dass die Einführung asynchroner Komponenten, die auf das Mounten warten oder erstellt werden, zu schlechten Praktiken führt, aber es ist nicht klar, ob dies der Fall ist. Zweitens stellt sich die Frage, selbst wenn diese schlechte Praktiken verursachen, sollten wir uns dafür entscheiden, sie zu beheben , anstatt sie als Rechtfertigung für die Schaffung neuer schlechter Praktiken zu verwenden. Wenn Sie von schlechten Praktiken wissen, die von v-if usw. erstellt werden, lade ich Sie ein, explizit (in einer anderen Ausgabe natürlich) das Problem mit diesen zu teilen, anstatt zu versuchen, dies als Rechtfertigung zu verwenden für eine andere Diskussion.

Ich habe diese Direktiven lediglich als Beispiel für Funktionen aufgezeigt, die fälschlicherweise verwendet werden können, um das Rendering einer Komponente zu blockieren, ähnlich wie Sie es über async... gesagt haben. Nichts ist falsch mit ihnen. Sollten wir also diese Direktiven entfernen, nur weil jemand "schlechte Praktiken" verwenden kann, um Komponenten zu erstellen, die eine Minute lang leere Seiten anzeigen? Tatsächlich sehen Sie niemanden, der das tut, weil es nicht passiert, es sei denn, Sie versuchen, ein Beispiel für äußerste Schlechtigkeit zu geben, wie in schrecklich.

Schauen Sie, der Punkt ist, wenn Sie noch keinen Anwendungsfall sehen können, dann sagen Sie nicht, dass andere Leute ihn schlecht verwenden werden und deshalb sollte es nicht gemacht werden. Schlechte Praktiken sind eine Frage der Unwissenheit und jemand, der unwissend ist, wird diese Funktionen möglicherweise niemals vollständig verwenden.

Da oben hat jemand https://github.com/vuejs/vue/issues/7209#issuecomment -424349370 gefragt und niemand hat ihm geantwortet, soweit ich das gesehen habe. Dies zeigt bei weitem, dass Vue in dieser Hinsicht hinterherhinkt. Dieser Teil der Architektur wurde entworfen, als Async noch keine Rolle spielte. Es ist also sicher eine gute Idee, es zu aktualisieren, um den modernen Anforderungen moderner Architekturen gerecht zu werden. Ansonsten ist der Rest hackig und Workarounds, die spezifische Methoden erfordern, anstatt das zu tun, was in der Branche passiert.

Ich bin mir jedoch noch nicht sicher, aber wenn man sich die neue funktionale API auf einen Blick ansieht, scheint dies tatsächlich möglich zu sein. Da es funktional ist, bedeutet dies, dass man bestimmte Dinge tun kann, die objektiv nicht möglich waren, wie zum Beispiel asynchrone Lebenszyklus-Hooks.

Schauen Sie, der Punkt ist, wenn Sie noch keinen Anwendungsfall sehen können, dann sagen Sie nicht, dass andere Leute ihn schlecht verwenden werden und deshalb sollte es nicht gemacht werden. Schlechte Praktiken sind eine Frage der Unwissenheit und jemand, der unwissend ist, wird diese Funktionen möglicherweise niemals vollständig verwenden.

Ich habe diesen Punkt nie erwähnt, ich möchte darauf hinweisen, dass ich standardmäßig asynchrone Aktionen ausführen möchte, ohne jemals das Rendern der Komponente zu blockieren. Es ist nicht intuitiv, dass das Ausführen von async Aktionen in einem mounted oder created Block das Rendern der Komponente verzögert. Angenommen, dies wäre der Fall, würde ich stattdessen sehen, dass die Komplexität daraus entsteht, wie ein Verbraucher, der die aktuelle Funktionalität wünscht, vorgehen würde. Das Argument bisher ist nicht, dass das, wonach gefragt wird, nicht getan werden kann, sondern dass das, wonach gefragt wird, die Standardeinstellung sein sollte. Sie können das Rendering Ihrer Komponente bereits blockieren, indem Sie die angezeigte Vorlage basierend auf einem v-if="loaded" wechseln.

Im Moment sieht das Rendern ohne Blockieren des Codes so aus:
Im Moment ist dieser Code:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
    this.loaded = true;
  }
</script>

Und das Rendern mit Blockieren sieht genauso aus, da Sie nicht wirklich blockieren können. Angenommen, async created() die Komponente tatsächlich blockiert. Dann haben wir jetzt eine Trennung von Code. Um den Spinner anzuzeigen, schreiben wir:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  created() { 
    this.loadData().then(() => this.loaded = true);
  }
</script>

und ignorieren Sie einfach das Rendern der Komponente auf dem Bildschirm, den wir schreiben

<template>
  <div>  
    <div>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
  }
</script>

Welchen Nutzen hat die Hinzufügung dieser Vereinfachung für die Sperrung des Vollstreckungsbescheids, die die Nichtsperrung komplizierter macht? Ich sehe es einfach nicht.

Abhängigkeitsbehandlung für Komponenten

@yyx990803 Bitte sehen Sie sich das an, es ist nicht perfekt, aber dennoch ein komplexes Anwendungsfall-Szenario.

Ok, hier ist ein Anwendungsfall, der elegant gehandhabt worden wäre, wenn Lebenszyklus-Hooks asynchron wären ...
_Ich wollte das eigentlich in einer App machen und bekam dafür hässlichen Code. Dies ist ein sehr konstruiertes Beispiel für coz_

Ich brauche Komponente A , um darauf zu warten, dass die mounted Hooks von Komponente B && C ausgelöst werden, bevor sie sich selbst einhängen. Also muss das mounted Komponente A auf seinen created Hook warten, der das Mounten von Komponente B && C ausgelöst hat, die auf den Trigger warteten _(der tatsächlich etwas vor dem Warten tun kann)_. Auf diese Weise ist es einfacher und viel sauberer und intuitiver, da für die betreffende Komponente alles an einem Ort bleibt.

A gibt ein Triggerereignis aus und lauscht auf Antworten von B und C _( B und C warten auf das Signal von A , bevor sie fortfahren, und geben dann Ereignisse aus, sobald sie montiert sind)_ bevor sie fortfahren, einfach. Dies ist eher ein Abhängigkeitsszenario für Komponenten ohne überflüssige Daten, die an anderer Stelle für die Zustandsverwaltung verstreut sind.

Haupt-Hosting-Komponente , alle Komponenten werden zusammen geladen, aber warten Sie mit Ereignissen und async auf die richtigen, warten Sie. Es ist egal, was diese Kinder tun, sie bestellen sich selbst.

<template>
  <div>
     ...
     <component-A/>
     <component-B/>
     <component-C/>
     ... other conent
  </div>
</template>
<script>
  import ComponentA...
  ...
  export default {
      components: { ComponentA... }
  }
</script>

Komponente A steuert die Montage von B und C als Abhängigkeiten. Die Auslösung könnte später in anderen Hooks oder sogar über ein UX-Event der gleichen Komponenten erfolgen. Das Folgende soll nur die Idee hier zeigen.

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here before mounting thrusters, even await it
         this.root.$emit('mount-thrusters');
         await Promise.all([
            this.wasMounted('thruster-1-mounted'), 
            this.wasMounted('thruster-2-mounted')
         ]); 
      },
      mounted() {
        // will only run after components B and C have mounted
        ...
      },

     methods: {
       wasMounted(compEvent) {
          return new Promise( (resolve)=>this.root.$once(compEvent, ()=>resolve()));
       }
    }
  }
</script>

Komponente B

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here, even await it, but happens at the same time as all components
         await new Promise( (resolve)=>this.root.$once('mount-thrusters', ()=>resolve()));
      },
     mounted() {
       this.root.$emit('thruster-1-mounted');
    }
  }
</script>

Komponente C

<template>
  ...
</template>
<script>
  export default {
      async created() {
          // ...do something here, even await it, but happens at the same time as all components
         await new Promise( (resolve)=>this.root.$once('mount-thrusters', ()=>resolve()));
      },
     mounted() {
       this.root.$emit('thruster-2-mounted');
    }
  }
</script>

Der obige Code kann durch Mixins weiter vereinfacht werden, da es viele doppelte Codeschnipsel gibt. Ich wollte nur, dass es klar ist. Die wasMounted-Methode kann in einem Mixin abgefüllt und für alle 3 Komponenten verwendet werden.

Hier können wir deutlich sehen, was jede Komponente erwartet, ohne dass ein anderer Hacker- oder Router-Code an anderer Stelle verstreut ist, um genau dasselbe zu steuern. Es ist sehr verwirrend, dies tatsächlich ohne diese Funktion zu tun, glauben Sie mir, ich habe dies in einer App getan.

Dadurch wird offensichtlich unnötig komplexer und nicht wartbarer Code beseitigt.

Stellen Sie sich das jetzt in einer großen App vor, mit 32 Triebwerkskomponenten, die sich anders verhalten. Sie haben nur etwa 3 Punkte zu beachten, die sich sogar auf 2 reduzieren lassen, wenn Sie Mixins einwerfen.

Damit die Dinge frisch bleiben

Dies ist natürlich nicht nur auf das Einhängen und Erstellen beschränkt, sondern sollte eigentlich mit allen anderen Lifecycle-Hooks funktionieren. Stellen Sie sich vor, dies wäre ein glänzender neuer beforeActivate / beforeUpdate Hook. Wir könnten die Komponente auf _Aktivierung/Aktualisierung_

Die Liste ist endlos, sobald dies implementiert ist.

Schauen Sie, der Punkt ist, wenn Sie noch keinen Anwendungsfall sehen können, dann sagen Sie nicht, dass andere Leute ihn schlecht verwenden werden und deshalb sollte es nicht gemacht werden. Schlechte Praktiken sind eine Frage der Unwissenheit und jemand, der unwissend ist, wird diese Funktionen möglicherweise niemals vollständig verwenden.

Ich habe diesen Punkt nie erwähnt, ich möchte darauf hinweisen, dass ich standardmäßig asynchrone Aktionen ausführen möchte, ohne jemals das Rendern der Komponente zu blockieren. Es ist nicht intuitiv, dass das Ausführen von async Aktionen in einem mounted oder created Block das Rendern der Komponente verzögert. Angenommen, dies wäre der Fall, würde ich stattdessen sehen, dass die Komplexität daraus entsteht, wie ein Verbraucher, der die aktuelle Funktionalität wünscht, vorgehen würde. Das Argument bisher ist nicht, dass das, wonach gefragt wird, nicht getan werden kann, sondern dass das, wonach gefragt wird, die Standardeinstellung sein sollte. Sie können das Rendering Ihrer Komponente bereits blockieren, indem Sie die angezeigte Vorlage basierend auf einem v-if="loaded" wechseln.

Im Moment sieht das Rendern ohne Blockieren des Codes so aus:
Im Moment ist dieser Code:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
    this.loaded = true;
  }
</script>

Und das Rendern mit Blockieren sieht genauso aus, da Sie nicht wirklich blockieren können. Angenommen, async created() die Komponente tatsächlich blockiert. Dann haben wir jetzt eine Trennung von Code. Um den Spinner anzuzeigen, schreiben wir:

<template>
  <div>  
    <spinner v-if="!loaded">
    <div v-else>
      ....
    </div>
</template>

<script>
  created() { 
    this.loadData().then(() => this.loaded = true);
  }
</script>

und ignorieren Sie einfach das Rendern der Komponente auf dem Bildschirm, den wir schreiben

<template>
  <div>  
    <div>
      ....
    </div>
</template>

<script>
  async created() { 
    await this.loadData();
  }
</script>

Welchen Nutzen hat die Hinzufügung dieser Vereinfachung für die Sperrung des Vollstreckungsbescheids, die die Nichtsperrung komplizierter macht? Ich sehe es einfach nicht.

Dies ist das Bootcamp von Vue 101 und es gibt dort nichts Neues ... es reicht zum Beispiel nicht aus, die oben genannten Fälle abzudecken. Die Idee hier ist, die Komplexität im Benutzerland zu reduzieren, in dem Vue tatsächlich verwendet wird, und leichter nachvollziehbaren Code zu verwenden.

Das Rendern ist hier nicht das Problem, sondern das, was vor dem Rendern passiert, ist tatsächlich von Bedeutung. Wir wollen die Freiheit, Dinge zu tun, bevor wir fortfahren oder eine Komponente rendern. Das hat aber auch nichts mit Blockieren des Renderings zu tun. Es gibt viele Lebenszyklus-Hooks, die Vue unterstützt, und diese können tatsächlich nützlich sein, wenn es eine Möglichkeit gäbe, asynchronen Code gegen andere Hooks zu handhaben. Die Idee ist, dass Vue intern asynchron respektiert, bevor es zur nächsten Hook-Funktion geht.

Ich bin wirklich verwirrt, anstatt B & C mit A zu koppeln, würde ich den Code verschieben, um A in A.js zu "laden" und dann A.js die "B.data" und "C.data" aktualisieren lassen. . Auf diese Weise werden die anderen Komponenten automatisch neu gerendert, wenn sich die A.data aus irgendeinem Grund ändern, anstatt zu versuchen, zu delegieren
Steuerung von einer Komponente zur anderen. Selbst im geteilten Fall würde ich die Daten zum Rendern von A von der Komponente A entkoppeln. Wir haben eine einzelne Klasse verwendet, die Methoden wie fetchData und hasInitialized enthält, wobei letztere ein Versprechen ist und erstere letztere auflöst.
Die direkte Kopplung der Komponenten erzeugt unerwartete Abhängigkeitsbäume, die verhindern, dass die Komponenten wiederverwendbar sind, und es vue ermöglicht, sie korrekt neu zu rendern.

Alternativ würde ich sogar emit das Ereignis direkt an das übergeordnete Element von A, B und C senden und nicht auf den globalen Gültigkeitsbereich, und das übergeordnete Element entscheiden lassen, ob B und C gerendert werden sollen, d

  <template>
    <a-component @rendered="showBandC = true" />
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>

Was ist mit A, das wir in diesem Fall tatsächlich rendern müssten, bevor B und C rendern. Wenn die Methode created() etwas enthält, hindert nichts dies daran, den Store über eine Javascript-Klasse zu füllen oder ein store Modul zu verwenden. Aber der explizite Use Case wäre hilfreicher, dh was ist die UX der User Story, die nicht erfasst werden kann?

Die Idee ist, dass Vue intern asynchron respektiert, bevor es zur nächsten Hook-Funktion geht.

Sicher, dieser Teil macht Sinn, aber ich bin mir nicht sicher, warum das Beispiel verworren sein muss, warum nicht einfach so etwas wie diese User Story sagen:

Meine Komponente hat sowohl async beforeMount als auch async mounted , aber der Code in mounted wird ausgelöst, bevor der Code in beforeMount abgeschlossen ist. Wie können wir verhindern, dass mounted ausgelöst wird, bevor beforeMount abgeschlossen ist?

Was die ursprüngliche Anfrage war, ist die Frage, die in der zweiten Antwort gestellt wurde, meiner Meinung nach immer noch relevant: https://github.com/vuejs/vue/issues/7209#issuecomment -350284784

Vorerst geschlossen, aber zögern Sie nicht, konkretere Argumente / Anwendungsfälle / Implikationen nachzuverfolgen.

Gibt es tatsächlich einen gültigen Anwendungsfall dafür, dass zuvor ausgeführte Lifecycle-Hooks blockiert werden müssen, oder ist es richtig, dass Lifecycle-Hooks synchron sind. Bisher war die Diskussion philosophischer Natur (wie es bei guten Architekturdiskussionen der Fall ist), aber die Frage ist wirklich, ob es dafür einen guten Grund gegeben hat. Ich zweifle keine Sekunde daran, dass es für das Framework vernünftig ist, auf asynchronen Code zu warten. Ich hatte genau das Problem in N anderen Bibliotheken, die dies nicht taten oder einen Rückruf übergeben (oder einen Rückruf übergeben, aber keinen Rückruf an den Rückruf übergeben). Es ist jedoch tatsächlich sinnvoll, einen asynchronen Lebenszyklus-Hook zu haben, oder liegen die Gründe im Ergebnis des Versuchs, etwas zu tun, das "nicht getan werden sollte"?

Dh was passiert, wenn man versucht, unmount eine Komponente zu created zu destroying eine, die noch nicht mounted , ich beneide den Implementierer dieser Funktionalität nicht.

Ich bin wirklich verwirrt, anstatt B & C mit A zu koppeln, würde ich den Code verschieben, um A in A.js zu "laden" und dann A.js die "B.data" und "C.data" aktualisieren lassen. . Auf diese Weise werden die anderen Komponenten automatisch neu gerendert, wenn sich die A.data aus irgendeinem Grund ändern, anstatt zu versuchen, zu delegieren

Das ist Komplexität gestiegen, schlechte Praxis. Versuchen Sie, es hier vollständig zu schreiben. Mal sehen, was Sie meinen, aber für mich haben Sie die Komplexität nur um ein Vielfaches erhöht.

Steuerung von einer Komponente zur anderen. Selbst im geteilten Fall würde ich die Daten zum Rendern von A von der Komponente A entkoppeln. Wir haben eine einzelne Klasse verwendet, die Methoden wie fetchData und hasInitialized enthält, wobei letztere ein Versprechen ist und erstere letztere auflöst.

Das koppelt die Komponenten jetzt zu sehr. Wir möchten, dass diese mit Ausnahme von A ohne die anderen funktionieren.

Die direkte Kopplung der Komponenten erzeugt unerwartete Abhängigkeitsbäume, die verhindern, dass die Komponenten wiederverwendbar sind, und es vue ermöglicht, sie korrekt neu zu rendern.

Tatsächlich verfehlen Sie den Punkt, diese sind so weit lose gekoppelt, dass jeder verwendet und gewartet werden kann, ohne den anderen zu beeinträchtigen. Tatsächlich können Sie jeden von ihnen mehrmals überall ablegen, ohne weiteren Code in die Eltern zu schreiben, außerhalb von <component-x /> , kein v-if , vuex, um seinen Zustand zu verwalten oder irgendetwas anderes.

Ich habe sie A mit B und C gekoppelt, nur um zu demonstrieren, ich hätte dies schön aufteilen oder einfach zählen können, wie viele Komponenten geantwortet haben, und dann fortfahren, wenn eine bestimmte erwartete Anzahl erreicht ist (in diesem Fall 2), z.

 this.$root.$emit('thruster-mounted') // in B and C
// instead of 
 this.$root.$emit('thruster-1-mounted') // for B and 2 for C

// then count the responses and resolve once they are >= 2 in component A

Wie auch immer, deswegen habe ich gesagt, Komponentenabhängigkeitsbehandlung, dies ist erwünscht und wird erwartet, aber mit so wenig Komplexität wie möglich gemacht, denn je komplexer es wird, desto unübersichtlicher wird es.

Alternativ würde ich sogar emit das Ereignis direkt an das übergeordnete Element von A, B und C senden und nicht auf den globalen Gültigkeitsbereich, und das übergeordnete Element entscheiden lassen, ob B und C gerendert werden sollen, d

Ich wusste, dass Sie das sagen würden, aber das ist unerwünscht. Diese Komponenten sollten von nichts anderem kontrolliert werden, daher habe ich betont, dass sich die Hauptkomponente nicht darum kümmert, was ihre Kinder tun, sie sollten unabhängig bleiben. Ich möchte sie überall in der App platzieren und trotzdem das Gleiche zum Laufen bringen . In dem Moment, in dem Sie tun, was Sie dort sagen, beobachten Sie, wie alles auseinanderbricht. Aber ich kann Komponenten buchstäblich überall im DOM-Baum platzieren, ohne auch nur zusammenzuzucken, und alles wird einfach funktionieren. Ich kann sogar mehrere Kopien davon haben und es wird immer noch funktionieren. Alles dank async ... await auf Lebenszyklen.

  <template>
    <a-component @rendered="showBandC = true" />
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>

Was ist mit A, das wir in diesem Fall tatsächlich rendern müssten, bevor B und C rendern.

Wir möchten, dass jede Komponente eine einzigartige Arbeit leistet, bevor sie montiert wird. Aber alle Komponenten werden erst gerendert, wenn alle anderen Komponenten diese Arbeit erledigt haben. Das ist die Geschichte hier.
Also viel Glück mit der Zustandsverwaltung und v-if nur, um dies zu kontrollieren, ganz zu schweigen von den tatsächlichen Daten, die es wahrscheinlich im vuex-Store produzieren wird . Am Ende wird viel doppelter Code geschrieben, wo immer die Komponente verwendet wird. Nehmen wir an, Sie haben eine andere Komponente, die nur A und C hostet und in einer anderen Konfiguration? Sie müssen diese v-if 's, Vuex State Management schreiben, damit das funktioniert. Siehst du das Problem? lass es mich veranschaulichen:

  // component Z totally different from foo, so we can't make this a component for reuse
  <template>
    <a-component @rendered="showBandC = true" />
    <c-component v-if="showBandC" />
  </template>
 ...
computed: {
showBandB() { ...vuex ...,
showBandC() { ...vuex ...,
}
  // component Foo totally unique, probably has other things it does
  <template>
    <b-component v-if="showBandC" />
    <c-component v-if="showBandC" />
  </template>
 ...
computed: {
// ok you could mixin this, fair, but complex nevertheless
showBandB() { ...vuex ...,
showBandC() { ...vuex ...,
}

..... und so weiter

anstatt nur die Komponenten zu verwenden, ohne jemals etwas in den Eltern zu tun, wie folgt:

  // component Z
  <template>
    <a-component />
    <b-component />
  </template>
  // component Foo
  <template>
    <b-component  />
    <c-component />
  </template>

... und so weiter

Wenn die Methode created() etwas enthält, hindert nichts dies daran, den Store über eine Javascript-Klasse zu füllen oder ein store Modul zu verwenden. Aber der explizite Use Case wäre hilfreicher, dh was ist die UX der User Story, die nicht erfasst werden kann?

Erinnern Sie sich, was ich über das überall verstreute Staatsmanagement gesagt habe? Wir möchten nicht, dass die Verwaltung dieser Komponenten bedeutet, dass wir viele Dinge anderswo verwalten, was sehr komplex ist, anstatt das, was ich gerade getan habe. Außerdem wird es nicht das tun, was ich will; Montieren Sie erst, wenn jede Komponente mit sehr geringem Aufwand das getan hat, was sie tun soll.

Die Idee ist, dass Vue intern asynchron respektiert, bevor es zur nächsten Hook-Funktion geht.

Sicher, dieser Teil macht Sinn, aber ich bin mir nicht sicher, warum das Beispiel verworren sein muss, warum nicht einfach so etwas wie diese User Story sagen:

Meine Komponente hat sowohl async beforeMount als auch async mounted , aber der Code in mounted wird ausgelöst, bevor der Code in beforeMount abgeschlossen ist. Wie können wir verhindern, dass mounted ausgelöst wird, bevor beforeMount abgeschlossen ist?

Der Punkt ist, dass die Dinge passieren, bevor eine dieser Komponenten gerendert und ohne zu viel Eingabe außerhalb der Komponenten selbst verwendet werden kann. Dies ist eine tatsächliche Sache, die mir aufgefallen ist, die ich hätte besser machen können, wenn diese App verfügbar wäre, die wir machen. Am Ende habe ich Code geschrieben, der viele Mixins, Vuex und stark gekoppelte Eltern überall hat (mit Mixins), die Komponenten wurden verwendet, weil dies fehlt. Dies ist keine verworrene Geschichte, ich erzähle Ihnen auf einfache Weise, was passiert ist. Wir mussten überdenken, wie die Benutzeroberfläche gestaltet und gewartet werden sollte. Es wurde optisch etwas weniger interessant und Code-technisch viel komplexer.

Sehen Sie, wie viele komplexe Dinge Sie in dieses einfache Setup eingeführt haben, das gerade durch dieses kleine asynchrone ... erwarten Feature in Lebenszyklen gelöst wurde?

@wparad

Dh was passiert, wenn Sie versuchen, eine Komponente zu unmounten, die noch nicht fertig erstellt wurde, wow, das wäre schlecht, noch darauf zu warten. Oder eine zu zerstören, die noch nicht fertig montiert ist, ich beneide den Implementierer dieser Funktionalität nicht.

Das ist wo:

... erfordert ein grundlegendes Überdenken/Neuschreiben der Architektur, um dies zu erreichen, und kann möglicherweise eine Menge Logik durchbrechen, die auf der synchronen Natur von Lebenszyklus-Hooks beruht ...

... ein Teil, von dem ich glaube, dass er von Ihnen erwähnt wurde. Wir brauchen eine Möglichkeit, mit diesen Randfällen umzugehen und wahrscheinlich noch mehr, die dadurch eingeführt werden. Mit anderen Worten, unsere Absichten müssen funktionieren, ohne dass die App abstürzt.

In all diesen Fällen würde ich Timeouts verwenden, um das Warten zu überprüfen oder abzubrechen, ähnlich wie bei den meisten asynchronen Vorgängen, die möglicherweise fehlschlagen.

Aber wenn Sie sich das von mir vorgestellte Beispiel genau ansehen, werden Sie verstehen, was ich meine. Dies hätte viele Dinge lösen können, ohne dass irgendwo viel Code geschrieben wurde. Tatsächlich hätte unsere App mit einer viel kleinen, defragmentierten und leicht verständlichen Codebasis viel besser sein können, wenn dies möglich wäre.
Das Besondere an dieser Art von Funktionen ist, dass Sie ihre Bedeutung erst erkennen, wenn Sie auf eine Straßensperre stoßen. Ich bin zum ersten Mal auf diese Seite gekommen, als wir an viele Workarounds für dieses Beispiel gedacht hatten, das ich gerade gegeben habe. Ich war nicht gekommen, um Hilfe zu suchen, sondern um eine Funktionsanfrage zu stellen, da wir festgestellt haben, dass sie in Vue nicht verfügbar war.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

robertleeplummerjr picture robertleeplummerjr  ·  3Kommentare

julianxhokaxhiu picture julianxhokaxhiu  ·  3Kommentare

Jokcy picture Jokcy  ·  3Kommentare

aviggngyv picture aviggngyv  ·  3Kommentare

hiendv picture hiendv  ·  3Kommentare