Heim >Web-Frontend >js-Tutorial >Erlernen des neuen Svelte-Veaktivitätssystems

Erlernen des neuen Svelte-Veaktivitätssystems

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-26 08:24:30223Durchsuche

Also wurde Svelte v5 veröffentlicht, die neueste Version des wahrscheinlich besten Front-End-Frameworks, das es gibt, und es unterscheidet sich erheblich von seiner Vorgängerversion. Der Hauptunterschied liegt im Kern: Wie die Reaktivität von Variablen implementiert wird. Aufgrund dieser Änderungen wurde Svelte einfacher und gleichzeitig etwas schwieriger.

Da ich seit v5@next.155 intensiv mit Svelte v5 in realen Micro-Frontend-Projekten arbeite, habe ich mich entschieden, diese Artikelserie zu schreiben, um mein gewonnenes Wissen an Sie weiterzugeben Verstehen, akzeptieren und migrieren Sie Ihren Code möglicherweise auf Svelte v5.

Eine kurze Einführung: Svelte v4 Reaktivität

Das Reaktivitätssystem von Svelte v4 ist nichts weniger als ein Kunstwerk: Svelte analysiert statisch Code in Komponenten und generiert dann Code, der das DOM zwingend ändert, wenn sich reguläre JavaScript-Variablen ändern. Einfach, elegant und sehr leistungsstark. Ein kurzes Beispiel:

<script lang="ts">
    let clickCount = 0;

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document on:click={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Diese einfache Komponente fügt dem Dokumentobjekt einen „Klick“-Ereignis-Listener hinzu und zählt Klicks. Die Klickzahl wird nur mit dem obigen Code in Echtzeit angezeigt. Erstaunlich, oder?

Wie alles im Leben ist es jedoch nicht perfekt. Rich Harris (der Erfinder von Svelte) hat die Vorbehalte erklärt, und ich werde in diesem Artikel nicht darauf eingehen. Ich möchte nur eines erwähnen: Code-Refactor.

Code-Refactoring ist nicht möglich

Einer der wichtigeren Vorbehalte ist die Unfähigkeit, dieses Reaktivitätssystem außerhalb der Komponente zu transportieren. Man kann beispielsweise kein wiederverwendbares Modul erstellen, das die Implementierung der countClicks-Funktion im Beispiel kapselt.

Da die Reaktivität von der statischen Analyse abhängt, wird durch das Wegnehmen der Funktion in ein Modul die Variablenmutation für den statischen Codeanalysator ausgeblendet, und dann geht die Reaktivität verloren.

Reaktivität in Svelte v5: Runen

Der Begriff Rune bezieht sich auf ein „magisches Symbol“ und ist der Begriff, den Svelte übernommen hat, um die folgenden funktionsähnlichen „magischen“ Begriffe zu benennen:

  • $state

  • $props

  • $bindbar

  • $abgeleitet

  • $effect

Die Reaktivität in Svelte v5 wird durch die Verwendung dieser Runen bestimmt.

Es ist wichtig zu beachten, dass sie zwar wie R-Werte aussehen, der erzeugte Code jedoch in Wirklichkeit L-Werte ist. Mit anderen Worten: Denken Sie nicht, dass Sie den Status von Variable zu Variable weitergeben können. Dies wird weiter unten im Abschnitt „$state-Rune“ etwas ausführlicher beschrieben.

Die Hauptvorteile dieses neuen Reaktivitätssystems sind:

  • Möglichkeit, reaktiven Code außerhalb von Komponenten umzugestalten

  • Feinkörnige Reaktivität

Ersteres bedeutet, dass wir reaktive Variablen außerhalb von Komponenten haben können; Letzteres bedeutet, dass das erneute Rendern von Komponenten zielgerichteter ist, wenn es darum geht, auf sich ändernde Zustände zu reagieren.

Die Möglichkeit, zustandsexterne Komponenten zu haben, wird in diesem Artikel nicht behandelt, aber folgen Sie der Reihe, da ein Artikel darüber folgen wird.

Feinkörnige Reaktivität bedeutet andererseits, dass Svelte jetzt wissen kann, welche Eigenschaft sich in einem Zustandsobjekt geändert hat, und nur das neu rendert (und Effekte erneut ausführt und abgeleitete Werte neu berechnet), was von dieser spezifischen Eigenschaft betroffen ist nur. Dies ist in einigen Fällen eine erhebliche Leistungsverbesserung. Ein kurzes Beispiel: Wenn einer großen Tabellenkomponente eine neue Zeile zu ihren Daten hinzugefügt wird, rendert Svelte nur die neue Zeile. Wenn sich ein einzelner Zellenwert in der 3. Zeile ändert, wird nur die Zelle neu gerendert, die den Wert anzeigt. Ist es jetzt klar? Hoffentlich ist es so, aber wenn nicht, schreiben Sie mir bitte im Kommentarbereich.

Die $state-Rune

Diese Rune wird verwendet, um einen reaktiven Zustand zu erzeugen. Schreiben wir das Svelte v4-Codebeispiel von oben neu:

<script lang="ts">
    let clickCount = 0;

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document on:click={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Um das gleiche Ergebnis wie in Svelte v4 zu erzielen, haben wir einfach $state(0) anstelle von 0 verwendet.

Die Hauptregel, die diese Rune regelt, ist, dass sie nur zum Initialisieren von Variablen oder Klassenfeldern verwendet werden kann, und sie hat mit dem wichtigen Hinweis zu tun, den Sie vor einer Minute gelesen haben: Runen sehen syntaktisch wie Funktionen aus, sind es aber nicht. Der Compiler ersetzt Runen durch Code, der nicht mit der Idee einer Funktion kompatibel ist, nämlich einen Wert zu berechnen und zurückzugeben. Das bedeutet, dass im Folgenden keine zweite reaktive Variable erstellt wird:

<script lang="ts">
    let clickCount = $state(0);

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document onclick={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Der reaktive Charakter von clickCount wird durch die Verwendung des Zuweisungsoperators nicht auf secondClickCount übertragen oder kopiert. Wenn Runen Funktionen wären, hätte das oben Genannte funktioniert, aber das sind sie nicht.

Es gibt noch etwas Wichtiges über $state zu erwähnen: Es macht seinen Wert äußerst reaktiv. Das heißt, wenn es sich bei dem Wert um ein Objekt handelt, dessen Eigenschaften Objekte enthalten, dann sind auch die Eigenschaften der enthaltenen Objekte reaktiv. Dieses Muster gilt rekursiv, sodass der gesamte Objektgraph letztendlich reaktiv ist.

Die $props-Rune

Es wird erwartet, dass Komponenteneigenschaften reaktiv sind, und Svelte v5 erreicht dies mithilfe der $props-Rune.

<script lang="ts">
    let clickCount = $state(0);
    let secondClickCount = clickCount;

    function countClicks() {
        ++clickCount;
    }
</script>

Da die Verwendung von TypeScript das A und O eines Projekts ist, beginnen wir mit der Deklaration der Komponenteneigenschaften mithilfe eines Typs. Optionale Eigenschaften werden durch das Anhängen von ? gekennzeichnet. zu seinem Namen.

Dann kommt die Verwendung der Rune, die eine destrukturierende Aussage ist. Das Beispiel zeigt, wie Sie Standardwerte zuweisen und „Rest“-Eigenschaften, also alle anderen Eigenschaften, zulassen. Die Komponente verteilt (wendet) diesen „Rest“ an Eigenschaften als Eigenschaften (Attribute) auf das Span-HTML-Element an.

Sie könnten let props tun: Props = $props(); um die Eigenschaften zu definieren, und es funktioniert, aber dann können Sie keine Standardwerte für die verschiedenen Eigenschaften angeben, daher schlage ich vor, dass Sie Eigenschaften immer wie gezeigt deklarieren. Ich wüsste übrigens auch nicht, wie man restProperties deklariert, wenn es nicht destrukturiert wäre.

Wenn Sie aufgepasst haben, führt das oben Gesagte zu einem TypeScript-Fehler. Schließlich erwähnt der Typ „Props“ keine „Rest“-Eigenschaft. Wie können wir restProps eingeben?

Im Allgemeinen können Sie Dinge wie die folgenden tun, um alle möglichen Dinge zuzulassen. Ich nehme an, es liegt an Ihren TypeScript-Kenntnissen.

Im Folgenden wird der Props-Typ geöffnet, um jedes data-*-Attribut zuzulassen:

<script lang="ts">
    let clickCount = 0;

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document on:click={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Dieser erlaubt alles:

<script lang="ts">
    let clickCount = $state(0);

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document onclick={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Aber in den meisten Fällen müsste man die Attribute des HTML-Elements zulassen, das restProps empfängt, und in unserem Beispiel war das das span-HTML-Element.

Für dieses häufige Szenario stellt Svelte v5 Typen bereit, die die meisten HTML-Elemente abdecken sollten:

<script lang="ts">
    let clickCount = $state(0);
    let secondClickCount = clickCount;

    function countClicks() {
        ++clickCount;
    }
</script>

Durch die Verwendung von Letzterem stellen GUIs wie VS Code genaues Intellisense für die möglichen Requisiten (Attribute) für das Span-HTML-Element bereit. Schön, oder?

Die HTMLAttributes Die Schnittstelle wird für HTML-Elemente verwendet, deren Eigenschaftenliste keine Besonderheiten aufweist. Viele Elemente haben es jedoch. Anstatt beispielsweise HTMLAttributes auszuführen, importieren Sie die HTMLButtonAttributes-Schnittstelle aus „svelte/elements“.

Das letzte Detail sind Standardwerte. Es gibt wirklich nicht viel zu sagen und das Beispiel sagt alles: Der Standardwert der Operation-Requisite ist „sum“. Wenn die Eigenschaft bei Verwendung der Komponente nicht angegeben wird, ist dies der Wert, den die Requisite annimmt.

Wenn die gewünschte Standardeinstellung undefiniert ist, geben Sie überhaupt nichts an.

Die $bindbare Rune

Dies ist eine sehr spezielle Rune, die nur in Komponenteneigenschaften verwendet werden kann. Es markiert eine Eigenschaft als bindbar.

Wenn Sie es nicht wissen oder sich nicht erinnern: Svelte ermöglicht die bidirektionale Bindung von Eigenschaften. Vue verfügt auch über diese Funktion, React dagegen nicht.

Die Verwendung ist super einfach:

<script lang="ts">
    type Props = {
        data: number[];
        operation?: 'sum', 'avg';
    };

    let {
        data,
        operation = 'sum',
        ...restProps,
    }: Props = $props();

    function sum() {
        return data.reduce((p, c) => p + c);
    }

    function avg() {
        return sum() / data.length
    }
</script>

<span class="amount" {...restProps}>{operation === 'sum' ? sum() : avg()}</span>

<style>
    .amount {
        font-family: monospace;
    }
</style>

Machen Sie Eigenschaften, deren Werte geändert werden, immer als bindbar, sonst beschwert sich Svelte mit einer Konsolenwarnung. Die Warnung besagt, dass Komponenten keinen Status ändern sollten, der nicht zu ihnen gehört, und dass, wenn dies beabsichtigt ist, eine Bindung verwendet werden sollte.

Wie im Beispiel gezeigt, kann man über die $bindable-Rune einen Eigenschaftsstandard festlegen. Das Beispiel setzt den Standardwert der Eigenschaft auf 5.

Aber macht eine Vorgabe hier überhaupt Sinn? Nun ja. Eine Eigenschaft als bindbar zu deklarieren, bedeutet nicht, dass sie erforderlich ist.

Die $abgeleitete Rune

Immer wenn wir einen Wert mithilfe von Werten aus Requisiten oder anderen reaktiven Zuständen (die sich im Laufe der Zeit ändern können) berechnen müssen, verwenden wir die Rune $derived.

Wir bringen die Beispielkomponente, die Summen und Durchschnittswerte berechnet, zurück und können sie mit dieser Rune umschreiben:

<script lang="ts">
    let clickCount = 0;

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document on:click={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Jetzt haben wir eine neue Variable namens result, die genauso reaktiv ist wie ihre Eingabe und jedes Mal automatisch eine Neuberechnung durchführt, wenn sich Daten im Datenarray ändern. Da es sich selbst um eine reaktive Variable handelt, wird auch die Vorlage (der HTML-Teil der Komponente), die sie verwendet, aktualisiert.

Die $effect-Rune

Mit dieser Rune können wir beliebigen Code angeben, der immer dann ausgeführt wird, wenn sich reaktive Daten ändern. Damit diese Rune ihre Magie entfalten kann, verfolgt sie die reaktiven Daten, die während ihrer Ausführung gelesen werden. Dieser Bestand an reaktiven Daten wird dann verwendet, um den Effekt erneut auszulösen, wenn irgendetwas im Bestand seinen Wert ändert.

Das wahrscheinlich häufigste Szenario besteht darin, einen Datenabrufvorgang basierend auf sich ändernden Werten erneut auszulösen:

<script lang="ts">
    let clickCount = $state(0);

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document onclick={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Asynchrone Operationen sind normalerweise die Norm innerhalb von Effekten, wenn wir nicht möchten, dass unsere $abgeleiteten Variablen Versprechen enthalten. Persönlich und weil es in Svelte so einfach ist, mit Versprechen zu arbeiten, würde ich jedoch einfach einen $abgeleiteten Wert verwenden. Die als nächstes gezeigte Variante macht Daten zu einem reaktiv berechneten Wert, der ein Versprechen hält:

<script lang="ts">
    let clickCount = $state(0);
    let secondClickCount = clickCount;

    function countClicks() {
        ++clickCount;
    }
</script>

Wenn Sie im Allgemeinen eine Kombination aus $state und $effect verwenden, sind Sie mit $derived höchstwahrscheinlich besser dran. Es gibt jedoch Ausnahmen von dieser Regel. Betrachten Sie sie also als Faustregel und nicht als das Heilige Wort.

Wenn das Abrufen von Daten kein gutes Beispiel für $effect ist, was dann? Schauen wir uns das hier an:

<script lang="ts">
    type Props = {
        data: number[];
        operation?: 'sum', 'avg';
    };

    let {
        data,
        operation = 'sum',
        ...restProps,
    }: Props = $props();

    function sum() {
        return data.reduce((p, c) => p + c);
    }

    function avg() {
        return sum() / data.length
    }
</script>

<span class="amount" {...restProps}>{operation === 'sum' ? sum() : avg()}</span>

<style>
    .amount {
        font-family: monospace;
    }
</style>

Dies ist eine einfache Timer-Komponente, die über ihre Statuseigenschaft gesteuert wird. Die Rune $effect wird hier verwendet, um den Betrieb des Timers zu erzwingen. Können Sie sich vorstellen, dies in $derived umzugestalten? Versuchen Sie es übrigens nicht, denn elapsed ist eine Requisite und kann daher nicht gleichzeitig $derived und Prop sein.

Abschluss

Svelte v5 verfügt über eine brandneue Reaktivitäts-Engine, die auf eine bessere Leistung beim erneuten Rendern und ein besseres Code-Refactoring ausgerichtet ist. Die Verwendung des neuen Reaktivitätssystems ist sowohl einfach als auch komplex: Einfach, weil die gängigen Szenarien durch das Systemdesign gut abgedeckt werden, und etwas schwieriger, weil der Code im Vergleich zu Version 4 etwas komplexer geworden ist.

Trotzdem ist das neue System leistungsstark und deckt die meisten Szenarien elegant und effektiv ab, indem es Runen für alle Möglichkeiten bereitstellt, die einfach zu verwenden sind, wenn auch zunächst etwas seltsam.

Was kommt als nächstes?

Dieser Artikel behandelt nur den Einführungsteil der Runen sowie einige persönliche Erfahrungen mit deren Verwendung. Es gibt noch weitere Themen zu behandeln, die Ihnen, Mitleser, dabei helfen sollen, mit dieser neuen Version von Svelte schneller voranzukommen, nämlich:

  • Fundiertes Wissen darüber, wie $effect funktioniert

  • Erweiterte Runen ($state.raw, $derived.by, $effect.pre usw.)

  • Speicher durch reaktiven Zustand ersetzen

  • Außergewöhnliche Szenarien

Bonus: Leistungsdiagramme

Sehen Sie sich diese Benchmark-Ergebnisse an: Interaktive Ergebnisse (krausest.github.io)

Jetzt ist die Liste der Frameworks erschreckend, Sie können also den folgenden JSON kopieren und ihn dann über die Schaltfläche „Einfügen“ in die Webseite einfügen (siehe Screenshot):

<script lang="ts">
    let clickCount = 0;

    function countClicks() {
        ++clickCount;
    }
</script>

<svelte:document on:click={() => countClicks()} />
<pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}

Learning the new Svelte veactivity System

Übrigens denke ich, dass es auch funktioniert, einfach das Fenster zu fokussieren und über die Tastatur einzufügen.

Dies schränkt die Liste der Frameworks auf die populäreren ein, oder zumindest auf das, was ich für beliebt halte. Vielleicht weißt du es besser als ich.

Es ist schade, dass Svelte v4 nicht mehr in den Charts verfügbar ist, aber wie Sie sehen können, sind von den ausgewählten Frameworks die Top 3 unbestritten: Vanilla JS, Solid und Svelte.

Am anderen Ende des Spektrums ist es einfach traurig zu sehen, dass React v19 so schlecht abschneidet. Sollte der Compiler es nicht viel besser machen? Es scheint, dass es sich letztendlich um vergebliche Mühe handelte. Sicher, es scheint React v18 zu übertreffen, aber das ist es auch schon. Warum Meta weiterhin Geld in React investiert, ist mir unklar. Gedanken, irgendjemand?

Das obige ist der detaillierte Inhalt vonErlernen des neuen Svelte-Veaktivitätssystems. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn