Johdanto toiminnalliseen reaktiiviseen ohjelmointiin Reduxissa

Aloitetaan aloittamalla perusajatus siitä, mikä "reaktiivinen ohjelmointi" on:

Reaktiivinen ohjelmointi on asynkroninen ohjelmointiparadigma, joka koskee datavirtoja ja muutosten etenemistä.

- Wikipedia

ReactiveX tai Rx on suosituin sovellusliittymä reaktiiviselle ohjelmoinnille. Se perustuu havainnoitavan mallin, iteraattorikuvion ja toiminnallisen ohjelmoinnin ideologioihin. Rx: llä on kirjastoja eri kielille, mutta käytämme RxJS: ää.

Rx perustuu havaittaviin , tarkkailijoihin ja operaattoreihin

Tarkkailija olennaisesti yhtyy on havaittavissa.

Tarkkailija lähettää sitten tietovirtoja, joita tarkkailija kuuntelee ja reagoi, käynnistämällä toimintaketjun datavirrassa. Todellinen voima tulee operaattoreista tai "reaktiivisista laajennuksista" (tästä johtuen termi Rx) .

Operaattorit antavat sinun muuttaa, yhdistää, manipuloida ja työskennellä Observablesin lähettämien kohteiden kanssa.

Jos et ole perehtynyt Rx: ään, sinulla voi olla vaikea ymmärtää ja käyttää Redux-Observable -ohjelmaa. Joten ehdotan, että likaat kätesi ensin Rx: n kanssa!

Nyt RxJS: n ja Reduxin kanssa.

Redux-havaittavissa

Redux-Observable on RxJS-pohjainen väliohjelmisto Reduxille

Tämä on mitä Redux Docsilla on sanottavaa Reduxin väliohjelmista:

Middleware tarjoaa kolmannen osapuolen laajennuspisteen toiminnan lähettämisen ja hetken välillä, jolloin se saavuttaa pelkistimen.

Redux-väliohjelmistoa voidaan käyttää kirjaamiseen, kaatumisraportointiin, puhumiseen asynkronisen API: n kanssa, reititykseen ja muuhun. Tai voimme sanoa haittavaikutuksia yleensä.

Joten miten Redux-Observable tekee kaiken?

Epicsin kautta. Eeppiset ovat Redux-Observable -aloitteen ydin primitiivisiä. Eepos on vain yksinkertainen toiminto, joka suorittaa toiminnon ja palauttaa sitten toisen toiminnan. Toiminto sisään → Toiminto ulos . Siksi toimia käsitellään virroina.

Jokainen React-komponentin lähetetty toiminta kulkee sellaisten toimintojen (eepos) läpi virtana.

Katsotaanpa, miltä yksinkertainen eepos, joka ottaa vastaan action'PING’ja palauttaa uuden,action'PONG’ näyttää:

const pingEpic = action$ => action$.filter(action => action.type === 'PING') .mapTo({ type: 'PONG' })

$Jälkeen actionkäytetään osoittamaan, että nämä muuttujat viitataan virtoja. Joten meillä on toimintavirta, joka on siirretty filtereeppiseen , johon olemme käyttäneet RxJS-operaattoria.

Tämä suodatinoperaattori suodattaa kaikki toiminnot, jotka eivät kuulu typePING! Siksi eepos pingEpickoskee vain type‘PING’. Lopuksi, tämä action‘PING’on kartoitettu uutta actionja type‘PONG’tyydyttää pääsäännön eeposten: Toiminta In → Action Out .

Koska jokainen eepos koskee vain tietyntyyppistä toimintaa, meillä on erityinen operaattori action$(suoratoisto) suodattamaan ei-toivotut toiminnot streamista. Tämä operaattori on ofType()operaattori.

Kirjoittamalla edellinen eepos uudella tavalla ofTypesaamme:

const pingEpic = action$ => action$.ofType('PING') .mapTo({ type: 'PONG' })

Jos haluat eeppinen antaa enemmän kuin yhden tyyppinen toimintaa, ofType()käyttäjä voi ottaa minkä tahansa määrän argumentteja näin: ofType(type1, type2, type3,...).

Eeppisten toimintojen yksityiskohtiin perehtyminen

Saatat ajatella, että toiminta 'PING' tulee yksinkertaisesti sisään ja syö tämän eepoksen. Siitä ei ole kysymys. Muista aina kaksi asiaa:

  1. Jokainen toiminto menee aina ensin pelkistimeen
  2. Vasta sen jälkeen eepos saa sen toiminnan

Siksi Redux-sykli toimii normaalisti kuten pitäisi.

Ensin action‘PING’saavutetaan vähennysventtiili, jonka sitten eeppinen vastaanottaa, ja vaihdetaan sitten uudeksi, action‘PONG’joka lähetetään vähennysventtiiliin.

Voimme jopa käyttää myymälän tilaa eepoksessa, koska eeppisen toinen argumentti on kevyt versio Redux Storesta! Katso alempaa:

const myEpic = (action$, store) =>

Voimme vain ca ll store.getState () ja päästä tilaan Epics.

Käyttäjän ketjutus

Toiminnon vastaanottamisen ja uuden lähettämisen välillä voimme tehdä kaikenlaisia ​​haluamiamme asynkronoituja sivuvaikutuksia, kuten AJAX-puhelut, verkkopistorasiat, ajastimet ja niin edelleen. Tämä tapahtuu käyttämällä lukuisia Rx: n tarjoamia operaattoreita .

Näiden Rx-operaattorien avulla voit säveltää asynkroniset sekvenssit deklaratiivisesti yhdessä kaikkien takaisinsoittojen hyötysuhteen kanssa, mutta ilman haittoja sisäkkäisiin takaisinsoittokäsittelijöihin, jotka yleensä liittyvät asynkronisiin järjestelmiin.

Saamme takaisinsoittojen edut ilman sitä pahamaineista "takaisinsoittohelvettiä".

Katso alla, kuinka voimme hyödyntää operaattoreiden voimaa.

Yleinen käyttötapaus

Oletetaan, että haluamme etsiä sanaa jollain sanakirjasovellusliittymällä, käyttämällä käyttäjän reaaliajassa kirjoittamaa tekstiä. Käsittelemme periaatteessa API-puhelun tallentamista (Redux-myymälässä) ja tulosten näyttämistä. Haluamme myös peruuttaa API-kutsun niin, että sovellusliittymä kutsutaan esimerkiksi yhden sekunnin kuluessa siitä, kun käyttäjä lopettaa kirjoittamisen.

Näin se tehdään käyttämällä Epic- ja RxJS-operaattoreita:

const search = (action$, store) => action$.ofType('SEARCH') .debounceTime(1000) .mergeMap(action => ajax.getJSON(`//someapi/words/${action.payload}`) .map(payload => ({ type: 'SET_RESULTS', payload })) .catch(payload => Observable.of({type: 'API_ERROR', payload})) )

Liikaa käsiteltäväksi?! Älä huoli, hajotetaan se.

Eepos saa kaiken toimintavirran oftype‘SEARCH’. Koska käyttäjä kirjoittaa jatkuvasti, jokaisen saapuvan toiminnon ( action.payload) hyötykuorma sisältää päivitetyn hakumerkkijonon.

The operator debounceTime() is used to filter out some of the actions in the stream except the last one. It basically passes an action through it only if 1 second has elapsed without it receiving another action or observable.

We then make the AJAX request, mapping the results to another action 'set_RESULTS' which takes the response data (payload) to the reducer, which is the Action Out part.

Any API errors are caught using the catch operator. A new action is emitted with the error details and later displays a toaster with the error message.

Notice how the catch is inside the mergeMap() and after the AJAX request? This is because the mergeMap() creates a chain that is isolated. Otherwise the error would reach ofType() and will terminate our Epic. If that happens, the Epic will stop listening to any action in the future!

We can use traditional promises for AJAX requests as well. However, they have this inherent problem of not being able to get cancelled. So another important use case for using Epics is AJAX cancellation.

We use the takeUntil operator to handle this issue. This is done just like we used that catch operator inside mergeMap and after the AJAX request.

This is because takeUntil must stop the current AJAX request and not the entire Epic! Therefore, isolating operator chains is important here as well.

Debouncing, throttling, filtering, AJAX cancellation and others, are just the tip of the iceberg. We have a myriad of operators at our disposal, making difficult use-cases trivial to solve. Using these operators, you can get as creative as your imagination allows you to be! Functional Reactive Programming (FRP) is elegant in its own way.

My focus for this article was on the explanation part of FRP in Redux using Redux-Observable. For setting up Redux-Observable in React+Redux, refer to the official docs — its very well documented, detailed, and easy-breezy.

Be sure to check out my other article on Redux which explores the best practice for creating reducers:

Reducing the Reducer Boilerplate With createReducer()

First, a quick recap of what reducers in Redux are:medium.freecodecamp.org

Haluatko parantaa JavaScript-perusteitasi? Lue nämä:

JavaScript ES6 -toiminnot: hyvät osat

ES6 tarjoaa hienoja uusia toiminnallisia ominaisuuksia, jotka tekevät JavaScriptin ohjelmoinnista paljon joustavampaa. Puhutaanpa ... medium.freecodecamp.org Opas JavaScript-muuttujien nostamiseen? let ja const kanssa

N EW JavaScript-kehittäjät usein vaikea ymmärtää ainutlaatuisen käyttäytymisen muuttuvan / toiminto hoisting.m edium.freecodecamp.org Tehtävä Nosto & Nosto Haastattelu Kysymykset

Tämä on osa 2 edellisestä Variable Hoisting -artikkelistani otsikolla “Opas JavaScript-muuttujan nostamiseen? kanssa… m edium.freecodecamp.org

Rauha ✌️