So führen Sie Benutzersuchen auf GitHub ohne React + RxJS 6 + Recompose durch

Dieser Artikel ist eine Antwort auf den Übersetzungsartikel „So suchen Sie Benutzer auf GitHub mit React + RxJS 6 + Recompose“ , in dem wir erst gestern gelernt haben, wie Sie React, RxJS und Recompose zusammen verwenden. Nun, ich schlage jetzt vor zu sehen, wie dies ohne diese Tools implementiert werden kann.




Haftungsausschluss
Es mag vielen scheinen, dass dieser Artikel Elemente des Trolling enthält, in Eile und auf einem Fan geschrieben wurde ... Also, das ist so.


Da dies ein Rückgabeartikel ist, habe ich beschlossen, ihn im gleichen Schritt-für-Schritt-Format wie das Original zu erstellen. Darüber hinaus soll der Artikel die ursprüngliche Implementierung mit der hier beschriebenen vergleichen. Daher enthält es eine Fülle von Referenzen und Zitaten aus dem Original. Fangen wir an.

Dieser Artikel richtet sich an Personen mit Erfahrung mit React und RxJS. Ich teile nur Vorlagen, die ich für das Erstellen einer solchen Benutzeroberfläche nützlich fand.

Dieser Artikel richtet sich an Personen mit Erfahrung mit Javascript (ES6), HTML und CSS. Außerdem werde ich in meiner Implementierung das "verschwindende" SvelteJS- Framework verwenden , aber es ist so einfach, dass Sie keine Erfahrung damit haben müssen, um den Code zu verstehen.

Wir machen das Gleiche:



Arbeiten ohne Klassen mit einem Lebenszyklus oder setState.

Ja, ohne Klassen, die mit einem Lebenszyklus oder setState arbeiten. Und auch ohne React, ReactDOM, RxJS, Recompose. Und außerdem, ohne componentFromStream, createEventHandler, combinLatest, map, startWith, setObservableConfig, BehaviorSubject, merge, of, catchError, delay, filter, map, zupfen, switchMap, tap, {ein weiterer Bullshit} ... Kurz gesagt, Sie verstehen.

Vorbereitung


Alles, was Sie brauchen, ist in meinem REPL-Beispiel auf der SvelteJS-Website. Sie können dort entweder lokal schnüffeln und die Quelle von dort herunterladen (Schaltfläche mit einem charakteristischen Symbol).

Erstellen Sie zunächst eine einfache Datei App.html, die die Stammkomponente unseres Widgets sein wird, mit den folgenden Inhalten:

<input placeholder="GitHub username"> <style> input { font-size: 20px; border: 1px solid black; border-radius: 3px; margin-bottom: 10px; padding: 10px; } </style> 


Im Folgenden verwende ich die Stile aus dem Originalartikel. Bitte beachten Sie, dass sie derzeit im Geltungsbereich sind, d. H. gelten nur für diese Komponente und Sie können Tag-Namen gegebenenfalls sicher verwenden.

Ich werde Stile direkt in die Komponenten schreiben, weil SFC und auch weil REPL den Export von CSS / JS / HTML in verschiedene Dateien nicht unterstützt, obwohl dies mit Svelte-Präprozessoren einfach möglich ist.

Neu komponieren


Ausruhen ...

Inline-Komponente


... Sonnenbaden ...

Konfiguration


... Kaffee trinken ...

+ RxJS neu zusammensetzen


... während andere ...

Karte


... arbeiten.

Fügen Sie einen Ereignishandler hinzu


Natürlich nicht wirklich ein Handler, nur eine Bindung:

 <input bind:value=username placeholder="GitHub username"> 


Nun, wir definieren den Standard-Benutzernamenwert:

 <script> export default { data() { return { username: '' }; } }; </script> 


Wenn Sie jetzt etwas in das Eingabefeld eingeben, ändert sich der Benutzername.


Ei und Huhn Problem


Keine Hühner, keine Eier, keine Probleme mit anderen Tieren, wir verwenden kein RxJS.

Zusammen stricken


Alles ist bereits reaktiv und verbunden. Also trinken wir Kaffee.

Benutzerkomponente


Diese Komponente ist für die Anzeige des Benutzers verantwortlich, dessen Namen wir an ihn übertragen. Es erhält einen Wert von der App-Komponente und übersetzt ihn in eine AJAX-Anfrage.

"Wow wow wow, nimm es ruhig" ©

Bei uns wird diese Komponente dumm sein und nur eine schöne Benutzerkarte nach einem bisher bekannten Modell anzeigen. Es spielt keine Rolle, woher die Daten stammen können und / oder an welcher Stelle der Schnittstelle wir diese Karte anzeigen möchten.

Die User.html-Komponente sieht ungefähr so ​​aus:

 <div class="github-card user-card"> <div class="header User" /> <a class="avatar" href="https://github.com/{login}"> <img src="{avatar_url}&s=80" alt={name}> </a> <div class="content"> <h1>{name || login}</h1> <ul class="status"> <li> <a href="https://github.com/{login}?tab=repositories"> <strong>{public_repos}</strong>Repos </a> </li> <li> <a href="https://gist.github.com/{login}"> <strong>{public_gists}</strong>Gists </a> </li> <li> <a href="https://github.com/{login}/followers"> <strong>{followers}</strong>Followers </a> </li> </ul> </div> </div> <style> /*  */ </style> 


Jsx / css


CSS wurde gerade zur Komponente hinzugefügt. Anstelle von JSX haben wir HTMLx in Svelte eingebettet.

Behälter


Der Container ist eine beliebige übergeordnete Komponente für die Benutzerkomponente. In diesem Fall ist es eine Komponente der App.

debounceTime


Das Debuggen der Texteingabe ist nicht sinnvoll, wenn die Operation nur den Wert im Datenmodell überschreibt. In der Bindung selbst brauchen wir das also nicht.

zupfen


Filter


Karte


Verbinden


Kehren wir zu App.html zurück und importieren Sie die Benutzerkomponente:

 import User from './User.html'; 


Datenanforderung


GitHub bietet eine API zum Abrufen von Benutzerinformationen:

Zur Demonstration schreiben wir einfach eine kleine api.js-Datei, die den Datenempfang abstrahiert und die entsprechende Funktion exportiert:

 import axios from 'axios'; export function getUserCard(username) { return axios.get(`https://api.github.com/users/${username}`) .then(res => res.data); } 


Und einfach so importieren wir diese Funktion in App.html.

Jetzt formulieren wir das Problem in einer spezifischeren Sprache: Wir müssen einen anderen Wert ändern, wenn wir einen Wert im Datenmodell (Benutzername) ändern. Wir nennen es jeweils Benutzer - Benutzerdaten, die wir von der API erhalten. Reaktivität in ihrer ganzen Pracht.

Schreiben Sie dazu eine berechnete Svelte-Eigenschaft mit der folgenden Konstruktion in App.html:

 <script> import { getUserCard } from './api.js'; ... export default { ... computed: { user: ({ username }) => username && getUserCard(username) } }; </script> 


Wenn Sie den Benutzernamen ändern, wird eine Anforderung zum Empfangen von Daten zu diesem Wert gesendet. Da Ordner jedoch auf jede Änderung reagieren, dh auf die Eingabe in ein Textfeld, werden zu viele Anforderungen gestellt, und wir werden alle verfügbaren Grenzwerte schnell überschreiten.

Im Originalartikel wird dieses Problem durch die in RxJS integrierte Funktion debounceTime gelöst, die verhindert, dass wir zu oft Daten anfordern. Für unsere Implementierung können Sie die eigenständige Lösung verwenden, z. B. Debounce-Versprechen oder eine andere geeignete Lösung, da Sie aus einer großen Auswahl wählen können.

 <script> import debounce from 'debounce-promise'; import { getUserCard } from './api.js'; ... const getUser = debounce(getUserCard, 1000); ... export default { ... computed: { user: ({ username }) => username && getUser(username) } }; </script> 


Diese Bibliothek erstellt also eine Debounce-Version der an sie übergebenen Funktion, die wir dann in der berechneten Eigenschaft verwenden.

switchMap


Ajax


RxJS bietet eine eigene Ajax-Implementierung, die hervorragend mit switchMap funktioniert!

Da wir kein RxJS und insbesondere switchMap verwenden, können wir jede Bibliothek verwenden, um mit Ajax zu arbeiten.

Ich benutze Axios, weil es für mich bequem ist, aber Sie können alles verwenden und es ändert nichts an der Essenz der Sache.

Versuchen Sie es


Zuerst müssen wir die Benutzerkomponente registrieren, um sie als Vorlagen-Tag zu verwenden, da der Import selbst die Komponente nicht zum Vorlagenkontext hinzufügt:

 <script> import User from './User.html'; ... export default { components: { User } ... }; </script> 

Trotz des scheinbar übermäßigen Kritzelns können unter anderem Instanzen derselben Komponente unterschiedliche Tag-Namen zugewiesen werden, wodurch Ihre Vorlagen semantisch verständlicher werden.

Ferner ist der Benutzerwert nicht die Daten selbst, sondern ein Versprechen für diese Daten. Da wir Freeloader sind und überhaupt keine Arbeit machen wollen, trinken Sie einfach Kaffee mit Keksen.

Um echte Daten an die Benutzerkomponente zu übertragen, können wir ein spezielles Design für die Arbeit mit Versprechungen verwenden:

 {#await user} <!--     --> {:then user} <!--      .    . --> {#if user} <User {...user} /> {/if} {/await} 

Es ist sinnvoll, das Vorhandensein des Datenobjekts zu überprüfen, bevor es an die Benutzerkomponente übergeben wird. Mit dem Spread-Operator können Sie ein Objekt beim Erstellen einer Instanz der Benutzerkomponente in separate Requisiten aufteilen.



Kürzere Arbeit.

Fehlerbehandlung


Versuchen Sie, einen nicht vorhandenen Benutzernamen einzugeben.
...
Unsere Anwendung ist kaputt.

Ihre wahrscheinlich ja, aber unsere ist definitiv nicht))) Es wird einfach nichts passieren, obwohl dies sicherlich nicht der Fall ist.

catchError


Fügen Sie einen zusätzlichen Block für die Verarbeitung abgelehnter Versprechen hinzu:

 {#await user} {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await} 


Komponentenfehler


 <div class="error"> <h2>Oops!</h2> <b>{response.status}: {response.data.message}</b> <p>Please try searching again.</p> </div> 

Jetzt sieht unsere Benutzeroberfläche viel besser aus:

Und nicht sagen, und vor allem keine Anstrengung.



Ladeanzeige


Kurz gesagt, dort begann eine weitere Häresie mit allen Arten von BehaviorSubjects und ähnlichen. Wir fügen nur eine Ladeanzeige hinzu und melken den Elefanten nicht:

 {#await user} <h3>Loading...</h3> {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await} 

Ergebnis?

Zwei winzige logiklose Komponenten (Benutzer und Fehler) und eine Steuerungskomponente (App), in denen die komplexeste Geschäftslogik in einer Zeile beschrieben wird - Erstellen einer berechneten Eigenschaft. Kein Bürsten von beobachtbaren Objekten von Kopf bis Fuß und Verbindungen +100500 Werkzeuge, die Sie nicht benötigen.

Interaktive Demo

Schreiben Sie einfachen und klaren Code. Schreiben Sie weniger Code, was weniger Arbeit und mehr Zeit mit Ihrer Familie bedeutet. Live!

Alles Glück und Gesundheit!

Alle :)


Fyi


Wenn Sie sich das Beispiel in REPL bereits angesehen haben, haben Sie den Toast wahrscheinlich mit einer Warnung von unten links bemerkt:
Kompiliert, aber mit 1 Warnung - überprüfen Sie die Konsole auf Details

Wenn Sie nicht zu faul sind, um die Konsole zu öffnen, wird folgende Meldung angezeigt:
Nicht verwendeter CSS-Selektor
.Benutzerkarte .Organisation {
Hintergrundposition: oben rechts;
}}

Svelte Static Analyzer informiert uns, dass einige Komponentenstile nicht verwendet werden. Darüber hinaus werden auf Ihre Anfrage oder den Befehl der Standard-Compiler-Einstellungen nicht verwendete Stile ohne Ihre Teilnahme aus dem endgültigen CSS-Bundle entfernt.

P / s


Lesen Sie weitere Artikel über Svelte und schauen Sie sich den russischsprachigen Telegrammkanal SvelteJS an . Wir freuen uns, Sie zu sehen!

Source: https://habr.com/ru/post/de419653/


All Articles