React, RxJS, partial.lenses
25th Nov 2019
React, RxJS, partial.lenses
Eli kuinka hallita tilaa RxJS:llä ja käyttää Reactia vain tilan renderöintiin*
(* React-komponentti voi silti hyödyntää paikallista tilaa)
25.11.2019
(demo)
Esitämme sovelluksen tilan puumaisena rakenteena (tilapuu), jonka juurena on objekti.
Haluamme tilapuun olevan immutable, jotta sen päivitys tapahtuu aina eksplisiittisesti:
fn(oldState) => newState
Tämä helpottaa ohjelman logiikan seuraamista ja vähentää bugeja.
Välitämme React-komponenteille vain tarvittavat osat tilapuusta.
Mikään React-komponentti ei voi mutatoida saamaansa tilapuun osaa.
Mahdollistamme tämän seuraavasti:
Käytämme JavaScriptin natiivia Arrayta ja Objektia
Object.freeze
ja freezeDeep
estävät mutatoinnin
Päivitämme puun osia partial.lenses-kirjastolla
partial.lenses on lens-abstraktiota käyttävä kirjasto, jolla voi hakea ja päivittää osia immutable-tietorakenteista, tuottaen niistä uusia versioita.
Kirjasto erottelee datan osoituksen (lenses) datan muuttamisesta.
Arvon päivitys objektiin:
const m = {a: {b: 1}, c: 2}
L.set(["a", "b"], 3, m) // => {a: {b: 3}, c: 2}
Objektien yhdistäminen:
const m = {a: {b: 1}}
L.assign("a", {c: 2}, m) // => {a: {b: 1, c: 2}}
{
// the last event triggering a change to the state; for self-inspection
lastEvent: {
type: string,
// plus event data, such as task id; depends on event type
},
// data model, to be consumed by React components
model: {
taskFilterText: string,
tasks: [
{id: uuid, isDone: boolean, name: string}
// ...
]
}
}
App
|
+- SearchTaskField
|
+- TaskList
| |
| +- Task
| +- Task
| `- Task
|
`- AddTaskField
Määritellään alkutila (startState
, useReducer
).
Tila välitetään propseina React-komponenteille.
Komponenteilla voi olla oma sisäinen tila, esimerkiksi tallentamaan
input-elementin teksti (useState
SearchTaskField
-komponentissa).
Tila ja komponentit päivittyvät Reactin hallinnoimista DOM-tapahtumista
(click
, keydown
; React controlled component).
(demo)
Kuinka päivittää komponentti DOM:n ulkopuolelta?
App
-komponentti renderöityy, vaikka normalisoitu hakuteksti ei muutu.
Single | Multiple | |
---|---|---|
Pull | function | Iterator |
Push | Promise | Observable |
Observable: producer of many values (events), pushes them to Observers (subscribers).
Each Observer gets an independent execution of the Observable subscribed to (unicast).
Subject: special Observable that allows shared execution to many Observers (multicast). Like pub-sub.
Tilaa hallitaan RxJS:llä, Reactilla renderöidään tila.
(demo)
(Palpatinen ähkäisy lopussa johtuu mahdollisen konffauksen määrästä.)
Sovellusten rakentaminen kirjastoilla, jotka sopivat hyvin yhteen, antaa paljon joustavuutta suunnitteluun.
Vertaa sovelluskehyksen käyttöön, jossa päätökset on jo tehty puolestasi. Sopiiko sovelluskehys ongelmaasi, tunnetko edes ongelmaa hyvin projektin alussa?
Mahdollistaa kirjastojen vaihtamisen, jos kirjastojen paradigma on suunnilleen samanlainen. Esimerkiksi:
Tilanhallinta on aina eksplisiittistä. Sinä olet ohjaksissa!
React-komponenttien koodi on intuitiivista.
"Great programmers write baby code"
– Eric Meijer, Principles of Reactive Programming -verkkokurssi
Deklaratiivinen API on aluksi hankala käyttää:
Soveltuu erityisen hyvin async-tapahtumien hallintaan.
Mahdolliset bugit johtuvat väärästä tavasta mallintaa tapahtumia (events).
RxJS on ollut olemassa useita vuosia. Vakaa ja suorituskykyinen.
Vaatii jonkin verran boilerplate-koodia, mikä voi aluksi turhauttaa.
Takaisinmaksu tulee toteuttaessa sovelluksia, joissa vaaditaan monimutkaista tilanhallintaa.
Tilanhallinnan yhdistävä Observable (stateO
) sijoittuu sovelluksen
ylimmälle tasolle.
Demon controller
-abstraktio on hieman kömpelö, mutta mielestäni
välttämätön, jottei actionS
(Subject) välity React-komponenteille
(liikaa valtaa).
(Esitys toteutettu Hacker's Tiny Slide Deckillä.)