GitHubi otsingufunktsioonide loomine rakenduses React koos RxJS 6 ja uuesti

See postitus on mõeldud neile, kellel on Reacti ja RxJS-i kogemus. Jagan lihtsalt kasutajaliidese loomisel kasulikke mudeleid.

Me ehitame järgmist:

Pole klasse, elutsükli konkse ega setState'i.

Seadistamine

Kõik on minu GitHubis.

git kloon https://github.com/yazeedb/recompose-github-ui
cd kompositsioon-github-ui
lõnga paigaldada

Peaharu on projekti lõpetanud, nii et kui soovite seda jälgida, siis kontrollige ka algharu.

git kassas algus

Ja käivitage projekt.

npm algus

Rakendus peaks töötama localhostis: 3000 ja siin on meie esialgne kasutajaliides.

Avage projekt oma lemmiktekstiredaktoris ja vaadake src / index.js.

Koostage uuesti

Kui te pole seda veel näinud, on recompose imeline Reacti utilihm komponentide funktsionaalseks programmeerimisstiiliks valmistamiseks. Sellel on palju funktsioone ja mul oleks raske oma lemmikuid valida.

See on Lodash / Ramda, aga Reacti jaoks.

Mulle meeldib ka see, et nad toetavad jälgitavaid. Tsiteerides dokumentidest:

Selgub, et suurt osa React Component API-st saab väljendada vaatlusega

Me rakendame seda kontseptsiooni juba täna!

Meie komponendi voogesitus

Praegu on rakendus tavaline Reakty komponent. Me saame selle tagastatava kaudu tagastada, kasutades selleks Rekombinatsiooni komponendiFromStreami funktsiooni.

See funktsioon muudab algselt nullkomponendi ja renderdab uuesti, kui meie vaadeldav annab uue väärtuse.

Kriips konfiguratsiooni

Voogude uuesti komponeerimine järgib ECMAScripti jälgitavat ettepanekut. Selles nähakse ette, kuidas vaatlejad peaksid töötama, kui nad lõpuks kaasaegsetesse brauseritesse toimetavad.

Kuni nende täieliku juurutamiseni loodame siiski sellistele raamatukogudele nagu RxJS, xstream, most, Flyd jne.

Rekombineerimine ei tea, millist teeki me kasutame, nii et see pakub komplekti SetObservableConfig, et teisendada ES vaatlusalused vajalikuks / vajalikuks.

Looge src-s uus fail nimega observableConfig.js.

Ja lisage see kood, et muuta kompoteerimine ühilduvaks RxJS 6-ga:

import {from} from 'rxjs';
impordi {setObservableConfig} 'kompositsioonist';
setObservableConfig ({
  fromESObservable: alates
});

Importige see index.js:

import './observableConfig';

Ja me oleme valmis!

Koostage uuesti + RxJS

Impordi komponentFromStreamist.

importida reageerida 'reageerima';
impordi ReactDOM 'react-dom'ist';
impordi {komponentFromStream} kaustast 'komponeeri';
import './styles.css';
import './observableConfig';

Ja hakake rakendust uuesti määratlema selle koodiga:

const App = komponentFromStream (prop $ => {
  ...
});

Pange tähele, et komponentFromStream võtab tagasihelistamise funktsiooni, oodates prop $ voogu. Idee on see, et meie rekvisiidid muutuvad jälgitavaks ja kaardistame need Reaxi komponendiks.

Ja kui olete kasutanud RxJS-i, tunnete väärtuste kaardistamiseks ideaalset operaatorit.

Kaart

Nagu nimest järeldada võib, muudate vaadeldava (millegi) vaadeldavaks (millekski muuks). Meie puhul vaadeldav (rekvisiidid) vaadeldavaks (komponent).

Importige kaardioperaator:

impordi {kaart} 'rxjs / operators' -st;

Ja määrake rakendus uuesti:

const App = komponentFromStream (prop $ => {
  tagasitulek $ .pipe (
    kaart (() => (
      
               
    ))   ) });

Alates RxJS 5-st kasutame operaatorite aheldamise asemel torusid.

Salvestage ja kontrollige oma kasutajaliidest, sama tulemus!

Ürituste käitleja lisamine

Nüüd muudame oma panuse natuke reageerivamaks.

Impordi saidist createEventHandler kataloogistEurustage.

impordi {komponentFromStream, createEventHandler} kaustast 'recompose';

Ja kasutage seda nii:

const App = komponentFromStream (prop $ => {
  const {käitleja, voog} = createEventHandler ();
  tagasitulek $ .pipe (
    kaart (() => (
      
               
    ))   ) });

createEventHandler on objekt, millel on kaks huvitavat omadust: käitleja ja voog.

Kapoti all on käitleja sündmuste emitter, mis surub väärtusi voogu, mis on jälgitav, mis edastab neid väärtusi oma abonentidele.

Seega ühendame vaadeldava voo ja vaadeldava voo $, et sisendi praegusele väärtusele juurde pääseda.

combLatest on siin hea valik.

Kana ja muna probleem

CombLatest'i kasutamiseks peavad siiski kiirgama nii stream kui ka prop $. voog ei kiirgu enne, kui rekv $ emiteerib, ja vastupidi.

Saame selle parandada, andes voole algväärtuse.

Impordi RxJS-i käivitusoperaatoriga:

impordi {map, startWith} kaustast 'rxjs / operators';

Ja looge muudetud voo jäädvustamiseks uus muutuja.

const {käitleja, voog} = createEventHandler ();
const väärtus $ = stream.pipe (
  kaart (e => e.target.value),
  startWith ('')
);

Me teame, et voog eraldab sündmusi sisendi onChange'is, seega kaardistame kohe iga sündmuse selle tekstiväärtuse juurde.

Lisaks lähtestame väärtuse $ tühjana stringina - see on tühise sisendi jaoks sobiv vaikeseade.

Ühendades selle kõik

Oleme valmis ühendama need kaks voogu ja importima combLatest loomise meetodina, mitte operaatorina.

importige {combLatest} failist 'rxjs';

Samuti saate kraanihalduri importida, et kontrollida väärtusi nende kujul:

importige {map, startWith, koputage} rakendusest 'rxjs / operators';

Ja kasutage seda nii:

const App = komponentFromStream (prop $ => {
  const {käitleja, voog} = createEventHandler ();
  const väärtus $ = stream.pipe (
    kaart (e => e.target.value),
    startWith ('')
  );
  tagastama combLatest (prop $, väärtus $). pipe (
    koputage (console.warn),
    kaart (() => (
      
               
    ))   ) });

Nüüd, kui tipite, logitakse [rekvisiidid, väärtus].

Kasutaja komponent

See komponent vastutab meile antud kasutajanime toomise / kuvamise eest. See saab väärtuse rakendusest ja kaardistab selle AJAX-kõnesse.

JSX / CSS

See kõik põhineb sellel vinge GitHubi kaartide projektil. Enamik asju, eriti stiile, on kopeeritud / kleebitud või ümber tehtud, et see sobiks Reakti ja rekvisiitidega.

Looge kaust src / User ja sisestage see kood User.css:

Ja see kood src / Kasutaja / Component.js:

Komponent täidab malli lihtsalt GitHub API standardse JSON-vastusega.

Konteiner

Nüüd, kui "loll" komponent on välja lülitatud, teeme "nutika" komponendi:

Siin on src / Kasutaja / index.js:

importida reageerida 'reageerima';
impordi {komponentFromStream} kaustast 'komponeeri';
import {
  debounceTime,
  filter,
  kaart,
  kitkuma
} andmebaasist 'rxjs / operators';
impordi komponent './komponendist';
import './User.css';
const Kasutaja = componentsFromStream (prop $ => {
  const getUser $ = prop $ .pipe (
    debounceTime (1000),
    kitk ('kasutaja'),
    filter (kasutaja => kasutaja && kasutaja pikkus),
    kaart (kasutaja => (
      

{kasutaja}

    ))   );
  tagasi getUser $;
});
eksporti vaikekasutaja;

Me defineerime Kasutaja komponendiksFromStream, mis tagastab prop $ voo, mis kaardistab väärtuse

.

debounceTime

Kuna kasutaja saab oma rekvisiidid klaviatuuri kaudu, ei taha me kuulata igat üksikut heidet.

Kui kasutaja hakkab tippima, jätab debounceTime (1000) kõik heitkogused 1 sekundiks vahele. Seda mustrit kasutatakse tavaliselt tüübikinnitustes.

kitkuma

See komponent eeldab mingil hetkel prop.userit. kitk haarab kasutaja, nii et me ei pea oma tugiteenuseid iga kord ümber struktureerima.

filter

Tagab, et kasutaja on olemas ega ole tühi string.

kaart

Praegu pange kasutaja lihtsalt sildi

alla.

Haakimine

Src / index.js-s tagasi kasutajakomponent importige:

impordi kasutaja './User';

Ja pakkuge väärtust kasutaja tugiteenusena:

  tagastama combLatest (prop $, väärtus $). pipe (
    koputage (console.warn),
    kaart (([rekvisiidid, väärtus]) => (
      
        
        
      
    ))   );

Nüüd kuvatakse teie väärtus ekraanile ühe sekundi pärast.

Hea algus, kuid peame kasutaja tõepoolest tooma.

Kasutaja toomine

GitHubi kasutajaliides on saadaval aadressil https://api.github.com/users/${user}. Saame selle hõlpsalt kasutaja / index.js siseselt abistajafunktsiooniks eraldada:

const formatUrl = user => `https://api.github.com/users/$ {user}`;

Nüüd saame lisada kaardi (formatUrl) pärast filtrit:

Võite märgata, et API lõpp-punkt kuvatakse ekraanile 1 sekundi pärast nüüd:

Kuid me peame tegema API taotluse! Siit tulevad switchMap ja ajax.

switchMap

Seda kasutatakse ka tüübikinnitustes. SwitchMap sobib suurepäraselt ühelt jälgitavalt teisele lülitamiseks.

Oletame, et kasutaja sisestab kasutajanime ja toome selle sisse lülituskaardile.

Mis juhtub, kui kasutaja sisestab midagi uut enne tulemuse tagasi jõudmist? Kas me hoolime eelmisest API vastusest?

Ei.

switchMap tühistab eelneva tõmbe ja keskendub praegusele.

ajax

RxJS pakub oma ajaxi rakendust, mis sobib suurepäraselt switchMapiga!

Nende kasutamine

Impordime mõlemad. Minu kood näeb välja selline:

import {ajax} kaustast 'rxjs / ajax';
import {
  debounceTime,
  filter,
  kaart,
  kitkuma,
  switchMap
} andmebaasist 'rxjs / operators';

Ja kasutage neid nii:

const Kasutaja = componentsFromStream (prop $ => {
  const getUser $ = prop $ .pipe (
    debounceTime (1000),
    kitk ('kasutaja'),
    filter (kasutaja => kasutaja && kasutaja pikkus),
    kaart (formaatUrl),
    switchMap (url =>
      ajax (URL) .pipe (
        kitk ('vastus'),
        kaart (komponent)
      )
    )
  );
  tagasi getUser $;
});

Lülituge meie sisendvoo juurest ajaxi päringule. Kui taotlus on täidetud, haarake selle vastus ja kaardistage meie komponent kasutajale.

Meil on tulemus!

Vigade käsitlemisel

Proovige sisestada kasutajanimi, mida pole olemas.

Isegi kui muudate seda, on meie rakendus katki. Rohkemate kasutajate toomiseks peate värskendama.

See on halb kasutajakogemus, eks?

catchError

Operaatoriga catchError saame vaikse murdmise asemel ekraanile mõistliku vastuse anda.

Importige see:

import {
  catchError,
  debounceTime,
  filter,
  kaart,
  kitkuma,
  switchMap
} andmebaasist 'rxjs / operators';

Ja kleepige see oma ajaxi ahela otsa.

switchMap (url =>
  ajax (URL) .pipe (
    kitk ('vastus'),
    kaart (komponent),
    catchError (({response}) => alarm (response.message))
  )
)

Vähemalt saame tagasisidet, kuid saame paremini hakkama.

Vigakomponent

Looge uus komponent, src / Error / index.js.

importida reageerida 'reageerima';

const Viga = ({vastus, olek}) => (
  
    

Vabandust!

           {status}: {response.message}          

Proovige uuesti otsida.

  
); eksport vaikimisi viga;

See kuvab kenasti meie AJAX-i kõne vastuse ja oleku.

Importime selle kausta Kasutaja / index.js:

impordi tõrge kaustast '../Error';

Ja RxJS-ist:

import {of} kaustast 'rxjs';

Pidage meeles, et meie komponentFromStreami tagasihelistamine peab tagastama vaadeldava. Me suudame selle saavutada.

Siin on uus kood:

ajax (URL) .pipe (
  kitk ('vastus'),
  kaart (komponent),
  catchError (tõrge => / ())
)

Jagage veaobjekt lihtsalt meie komponendi rekvisiitidena.

Kui me kontrollime oma kasutajaliidest:

Palju parem!

Laadimisnäidik

Tavaliselt nõuame nüüd mingisugust riigijuhtimist. Kuidas muidu laaditakse laadimisnäidik?

Kuid enne setState'i jõudmist vaatame, kas RxJS võib meid aidata.

Ühenda dokumendid panid mind mõtlema selles suunas:

SetState () asemel ühendage mitu voogu kokku.

Redigeerimine: Algselt kasutasin BehaviorSubjectsit, kuid Matti Lankinen vastas selle koodi lihtsustamiseks hiilgavalt. Aitäh Matti!

Importige ühendamise operaator.

impordi {merge, of} kaustast 'rxjs';

Kui taotlus on esitatud, liidame meie ajaxi laadimiskomponendi vooga.

SisekomponentFromStream:

const Kasutaja = componentsFromStream (prop $ => {
  const loading $ = of (

laadimine ...

);   const getUser $ = ...

Lihtne h3 laadimisnäidik muutus jälgitavaks! Ja kasutage seda nii:

const loading $ = of (

laadimine ...

);
const getUser $ = prop $ .pipe (
  debounceTime (1000),
  kitk ('kasutaja'),
  filter (kasutaja => kasutaja && kasutaja pikkus),
  kaart (formaatUrl),
  switchMap (url =>
    ühendada (
      laadimine $,
      ajax (URL) .pipe (
        kitk ('vastus'),
        kaart (komponent),
        catchError (tõrge => / ())
      )
    )
  )
);

Mulle meeldib, kui lühike see on. SwitchMapisse sisenedes ühendage laadivad $ ja ajax vaatlused.

Kuna $ laadimine on staatiline väärtus, emiteeritakse see kõigepealt. Kui asünkroonne ajax on lõpule jõudnud, siis see kiirgub ja kuvatakse ekraanil.

Enne selle testimist saame importida viivitusoperaatori, nii et üleminek ei toimu liiga kiiresti.

import {
  catchError,
  debounceTime,
  viivitus,
  filter,
  kaart,
  kitkuma,
  switchMap,
  koputage
} andmebaasist 'rxjs / operators';

Ja kasutage seda vahetult enne kaarti (komponent):

ajax (URL) .pipe (
  kitk ('vastus'),
  viivitus (1500),
  kaart (komponent),
  catchError (tõrge => / ())
)

Meie tulemus?

Ma mõtlen, kui kaugele seda mustrit on vaja võtta ja mis suunas. Palun jätke kommentaar ja jagage oma mõtteid!

Ja pidage meeles, et hoidke seda plaksutamisnuppu. (Võite minna kuni 50!)

Järgmise korrani.

Ole tubli,
Yazeed Bzadough
http://yazeedb.com/