Immutable.JS:n käyttö Reduxin kanssa#

Sisällysluettelo#

  • Miksi minun pitäisi käyttää Immutable.JS:n kaltaista muuttumattomuuteen keskittyvää kirjastoa?
  • Miksi minun pitäisi valita Immutable.JS muuttumattomaksi kirjastoksi?
  • Mitä ongelmia Immutable.JS.JS?
  • Onko Immutable.JS vaivan arvoinen?
  • Mitkä ovat joitain mielipiteitä parhaista käytännöistä Immutable.JS:n käyttämiseen Reduxin kanssa?

Miksi minun pitäisi käyttää Immutable.JS:n kaltaista immutable-fokusoitua kirjastoa?#

Immutable.JS:n kaltaisia immutable-fokusoituja kirjastoja kuten Immutable.JS on suunniteltu voittamaan JavaScriptille ominaiset muuttumattomuuteen liittyvät ongelmat ja tarjoamaan kaikki muuttumattomuuden edut sovelluksesi vaatimalla suorituskyvyllä.

Käytätkö tällaista kirjastoa vai pysytkö tavallisessa JavaScriptissä, riippuu siitä, kuinka mielellään lisäät sovellukseesi uuden riippuvuuden tai kuinka varma olet siitä, että pystyt välttämään JavaScriptin muuttumattomuuden lähestymistapaan liittyvät sudenkuopat.

Valitsitpa minkä vaihtoehdon tahansa, varmista, että tunnet muuttumattomuuden, sivuvaikutusten ja mutaation käsitteet. Varmista erityisesti, että sinulla on syvällinen ymmärrys siitä, mitä JavaScript tekee päivittäessäsi ja kopioidessasi arvoja, jotta voit suojautua vahingossa tapahtuvilta mutaatioilta, jotka heikentävät sovelluksesi suorituskykyä tai rikkovat sen kokonaan.

Lisätietoja#

Dokumentaatio

  • Reseptit: Muuttumattomuus, sivuvaikutukset ja mutaatio

Artikkelit

  • Introduction to Immutable.js ja funktionaalisen ohjelmoinnin käsitteet
  • Muuttumattomuuden käytön hyvät ja huonot puolet React.js:n kanssa

Miksi valita Immutable.JS muuttumattomaksi kirjastoksi?#

Immutable.JS suunniteltiin tarjoamaan muuttumattomuutta suorituskykyisellä tavalla pyrkimyksenä voittaa JavaScriptin muuttumattomuuden rajoitukset. Sen periaatteellisia etuja ovat:

Taattu muuttumattomuus#

Immutable.JS-objektiin kapseloitua dataa ei koskaan muuteta. Uusi kopio palautetaan aina. Tämä eroaa JavaScriptistä, jossa jotkin operaatiot eivät mutatoi dataa (esim. jotkin Array-metodit, kuten map, filter, concat, forEach jne.), mutta jotkin mutatoivat (Array:n pop, push, splice jne.).

Runsas API#

Immutable.JS tarjoaa runsaan joukon muuttumattomia objekteja datan kapseloimiseksi (esim.esim. kartat, luettelot, joukot, tietueet jne.) ja laajan joukon metodeja niiden käsittelyyn, mukaan lukien metodit tietojen lajitteluun, suodattamiseen ja ryhmittelyyn, käänteistämiseen, tasoittamiseen ja osajoukkojen luomiseen.

Suorituskyky#

Immutable.JS tekee paljon työtä kulissien takana suorituskyvyn optimoimiseksi. Tämä on sen tehon avain, sillä muuttumattomien tietorakenteiden käyttämiseen voi liittyä paljon kallista kopiointia. Erityisesti suurten, monimutkaisten tietokokonaisuuksien, kuten sisäkkäisen Reduxin tilapuun, muuttumaton manipulointi voi tuottaa monia välikopioita objekteista, jotka kuluttavat muistia ja hidastavat suorituskykyä selaimen roskienkerääjän taistellessa asioiden siivoamisesta.

Immutable.JS välttää tämän jakamalla datarakenteita fiksusti pinnan alla, mikä minimoi tiedon kopioinnin tarpeen. Se mahdollistaa myös monimutkaisten operaatioketjujen suorittamisen ilman, että luodaan tarpeettomia (ja kalliita) kloonattuja välitietoja, jotka heitetään nopeasti pois.

Et tietenkään koskaan näe tätä – Immutable.JS-objektiin antamiasi tietoja ei koskaan muuteta. Pikemminkin Immutable.JS:n sisällä metodikutsujen ketjutetusta sarjasta syntyvä välitieto on vapaasti mutatoitavissa. Näin ollen saat kaikki muuttumattomien tietorakenteiden edut ilman mitään (tai hyvin vähän) mahdollisia suorituskykyhaittoja.

Lisätietoja#

Artikkelit

  • Immutable.js, pysyvät tietorakenteet ja rakenteellinen jakaminen
  • PDF: JavaScript Immutability – Don’t go changing

Kirjastot

  • Immutable.js

Mitä ongelmia Immutable.JS:n käyttöön liittyy?#

Vaikka se onkin tehokas, Immutable.JS:ää on käytettävä varovasti, sillä siihen liittyy omat ongelmansa. Huomaa kuitenkin, että kaikki nämä ongelmat voidaan voittaa melko helposti huolellisella koodauksella.

Vaikea tehdä yhteistyötä#

JavaScript ei tarjoa muuttumattomia tietorakenteita. Jotta Immutable.JS voi tarjota muuttumattomuustakuunsa, datasi on kapseloitava Immutable.JS-objektiin (kuten Map tai List jne.). Kun tiedot on suljettu tällä tavalla, niiden on vaikea toimia muiden, tavallisten JavaScript-objektien kanssa.

Et esimerkiksi voi enää viitata objektin ominaisuuksiin tavallisella JavaScript-piste- tai sulkuesimerkinnällä. Sen sijaan niihin on viitattava Immutable.JS:n get()– tai getIn()-metodeilla, jotka käyttävät hankalaa syntaksia, jossa ominaisuuksiin päästään käsiksi merkkijonojoukon avulla, joista kukin edustaa ominaisuuden avainta.

Käyttäisit esimerkiksi myObj.prop1.prop2.prop3:n sijasta myImmutableMap.getIn().

Tämä tekee hankalaksi yhteentoimivuuden paitsi oman koodisi myös muiden kirjastojen, kuten lodashin tai ramdan, kanssa, jotka odottavat tavallisia JavaScript-objekteja.

Huomaa, että Immutable.JS-objekteilla on toJS()-metodi, joka palauttaa tiedot tavallisena JavaScript-tietorakenteena, mutta tämä metodi on erittäin hidas, ja sen laajamittainen käyttö mitätöi Immutable.JS:n tarjoamat suorituskykyedut

Kun Immutable.JS:ää on kerran käytetty, se leviää kaikkialle koodipohjaasi#

Kun olet kapseloinut tietosi Immutable.JS:n, joudut käyttämään Immutable.JS:n get() tai getIn() ominaisuuden accessoreita päästäksesi käsiksi siihen.

Tällä on se vaikutus, että Immutable.JS leviää koko koodipohjaasi, mukaan lukien mahdollisesti komponenttisi, joissa et ehkä halua olla tällaisia ulkoisia riippuvuuksia. Koko koodipohjasi on tiedettävä, mikä on ja mikä ei ole Immutable.JS-objekti. Se tekee myös Immutable.JS:n poistamisen sovelluksestasi vaikeaksi tulevaisuudessa, jos se joskus on tarpeen.

Tämän ongelman voi välttää irrottamalla sovelluslogiikkasi tietorakenteista, kuten alla olevassa Parhaat käytännöt -osiossa kerrotaan.

Ei destrukturointia tai hajautusoperaattoreita#

Koska joudut käyttämään tietojasi Immutable.JS:n omien get()– ja getIn()-metodien kautta, et voi enää käyttää JavaScriptin destrukturointioperaattoria (tai ehdotettua Object spread -operaattoria), mikä tekee koodistasi työläämpää.

Ei sovellu pienille arvoille, jotka muuttuvat usein#

Immutable.JS toimii parhaiten datakokoelmille, ja mitä suuremmat, sitä parempi. Se voi olla hidas, kun datasi koostuu monista pienistä, yksinkertaisista JavaScript-objekteista, joista jokainen koostuu muutamasta avaimesta primitiivisiä arvoja.

Huomaa kuitenkin, että tämä ei päde Reduxin tilapuuhun, joka esitetään (yleensä) suurena kokoelmana dataa.

Vaikea vianmääritys#

Immutable.JS-objekteja, kuten Map, List, jne, voi olla vaikea debugata, koska tällaisen objektin tarkastaminen paljastaa kokonaisen sisäkkäisen hierarkian Immutable.JS-kohtaisia ominaisuuksia, joista et välitä, kun taas varsinainen datasi, josta välität, on kapseloitu useita kerroksia syvemmälle.

Tämän ongelman ratkaisemiseksi voit käyttää selainlaajennusta, kuten Immutable.JS Object Formatteria, joka tuo datasi pintaan Chromen Dev Tools -ohjelmassa ja piilottaa Immutable.JS:n ominaisuudet dataa tarkastettaessa.

Rikkoo objektiviittaukset, mikä aiheuttaa huonon suorituskyvyn#

Yksi muuttumattomuuden tärkeimmistä eduista on se, että se mahdollistaa pinnallisen tasa-arvotarkastuksen, mikä parantaa suorituskykyä dramaattisesti.

Jos kaksi eri muuttujaa viittaa samaan muuttumattomaan objektiin, pelkkä molempien muuttujien tasa-arvotarkastus riittää sen toteamiseen, että ne ovat tasa-arvoisia ja että objekti, johon molemmat viittaavat, on muuttumaton. Yhdenvertaisuustarkastuksen ei tarvitse koskaan tarkistaa minkään objektin ominaisuuden arvoja, koska se on tietenkin muuttumaton.

Mutta matala tarkastus ei toimi, jos Immutable.JS-objektin sisään kapseloitu data on itse objekti. Tämä johtuu siitä, että Immutable.JS:n toJS()-metodi, joka palauttaa Immutable.JS-objektin sisältämän datan JavaScript-arvona, luo uuden objektin joka kerta, kun sitä kutsutaan, ja rikkoo siten viittauksen kapseloidun datan kanssa.

Näin ollen esimerkiksi kutsuminen toJS() kahdesti ja tuloksen osoittaminen kahdelle eri muuttujalle aiheuttaa sen, että näiden kahden muuttujan tasa-arvotarkistus epäonnistuu, vaikka itse objektien arvot eivät ole muuttuneet.

Tämä on erityinen ongelma, jos käytät toJS():tä käärityn komponentin mapStateToProps-funktiossa, koska React-Redux vertaa pinnallisesti jokaista palautetun props-objektin arvoa. Esimerkiksi alla olevan mapStateToProps:n palauttaman todos-prop:n viittaama arvo on aina eri objekti, joten se epäonnistuu matalassa tasa-arvotarkastuksessa.

// AVOID .toJS() in mapStateToProps
function mapStateToProps(state) {
return {
todos: state.get(’todos’).toJS() // Aina uusi objekti
}
}

Copy

Kun pinnallinen tarkistus epäonnistuu, React-Redux saa komponentin renderöitymään uudelleen. toJS():n käyttäminen mapStateToProps:ssa tällä tavalla aiheuttaa siis aina komponentin uudelleenrenderöinnin, vaikka arvo ei koskaan muuttuisi, mikä vaikuttaa voimakkaasti suorituskykyyn.

Tämä voidaan estää käyttämällä toJS():aa korkeamman järjestyksen komponentissa, kuten alla olevassa Parhaat käytännöt -osiossa on käsitelty.

Lisätietoa#

Artikkelit

  • Immutable.js, pysyvät tietorakenteet ja rakenteiden jakaminen
  • Immutable Data Structures and JavaScript
  • React.js pure render performance anti-pattern
  • Building Efficient UI with React and Redux

Chrome Extension

  • Immutable Object Formatter

Onko Immutable.JS:n käyttäminen vaivan arvoista?#

Frequently, yes. On olemassa erilaisia kompromisseja ja mielipiteitä harkittavaksi, mutta on monia hyviä syitä käyttää Immutable.JS:ää. Älä aliarvioi vaikeutta yrittää jäljittää tilapuusi ominaisuutta, joka on vahingossa mutantunut.

Komponentit sekä renderöivät uudelleen, kun niiden ei pitäisi, että kieltäytyvät renderöimästä, kun niiden pitäisi, ja renderöintiongelman aiheuttavan bugin jäljittäminen on vaikeaa, koska virheellisesti renderöivä komponentti ei välttämättä ole se, jonka ominaisuuksia on vahingossa mutantunut.

Ongelma aiheutuu pääasiassa mutantuneen tila-olion palauttamisesta Redux-reduktorista. Immutable.JS:n avulla tätä ongelmaa ei yksinkertaisesti ole olemassa, jolloin sovelluksestasi poistuu kokonainen luokka vikoja.

Tämän sekä sen suorituskyvyn ja datan manipulointiin tarkoitetun rikkaan API:n vuoksi Immutable.JS on vaivan arvoinen.

Lisätietoja#

Dokumentaatio

  • Vianetsintä: Mitään ei tapahdu, kun lähetän toiminnon

Mitkä ovat joitain mielestäni parhaita käytäntöjä Immutable.JS:n käyttämiseen Reduxin kanssa?#

Immutable.JS voi tarjota merkittäviä luotettavuus- ja suorituskykyparannuksia sovellukseesi, mutta sitä on käytettävä oikein. Jos päätät käyttää Immutable.JS:ää (ja muista, että sinun ei ole pakko käyttää sitä, ja voit käyttää muitakin muuttumattomia kirjastoja), noudata näitä lausunnolla olevia parhaita käytäntöjä, niin saat siitä kaiken mahdollisen irti kompastumatta ongelmiin, joita se voi mahdollisesti aiheuttaa.

Älä koskaan sekoita tavallisia JavaScript-objekteja Immutable.JS:n kanssa#

Ei koskaan saa antaa tavallisen JavaScript-objektin sisältää Immutable.JS:n ominaisuuksia. Samoin älä koskaan anna Immutable.JS-objektin sisältää tavallista JavaScript-objektia.

Lisätietoja#

Artikkelit

  • Immutable Data Structures and JavaScript

Tee koko Redux-tilapuustasi Immutable.JS-objekti#

Redux-sovelluksessa koko tilapuun tulisi olla Immutable.JS-objekti, eikä tavallisia JavaScript-objekteja käytetä lainkaan.

  • Luo tilapuu käyttämällä Immutable.JS:n fromJS()-funktiota.

  • Käytä Immutable.JS-tietoinen versio combineReducers-funktiosta, kuten redux-immutable-funktiossa, koska Redux itse odottaa tilapuun olevan tavallinen JavaScript-objekti.

  • Kun lisäät JavaScript-objekteja Immutable.JS-karttaan tai -luetteloon käyttämällä Immutable.JS:n update, merge tai set metodeja, varmista, että lisättävä objekti muunnetaan ensin Immutable-objektiksi käyttämällä fromJS().

Esimerkki

// vältä
const newObj = { key: value }
const newState = state.setIn(, newObj)
// newObj on lisätty tavallisena JavaScript-oliona, EI Immutable.JS Map
// suositellaan
const newObj = { key: value }
const newState = state.setIn(, fromJS(newObj))
// newObj on nyt Immutable.JS Map

Kopioi

Lisätietoja#

Artikkelit

  • Immutoituvat tietorakenteet ja JavaScriptiä

Kirjastot

  • redux-immutoituva

Käytä Immutable.JS kaikkialla muualla paitsi tyhmissä komponenteissasi#

Käyttämällä Immutable.JS:ää kaikkialla pidät koodisi suorituskykyisenä. Käytä sitä älykkäissä komponenteissasi, valikoijissasi, saagoissasi tai thunkeissasi, action-luojissasi ja erityisesti reduktoreissasi.

Älä kuitenkaan käytä Immutable.JS:ää tyhmissä komponenteissasi.

Lisätietoja#

Artikkelit

  • Muuttumattomat tietorakenteet ja JavaScript
  • Älykkäät ja tyhmät komponentit Reactissa

Rajoita toJS()#

toJS() käyttöäsi on kallis funktio, ja se mitätöi Immutable.JS:n käytön tarkoituksen. Vältä sen käyttöä.

Lisätietoja#

Keskustelut

  • Lee Byron Twitterissä: ”Perf tip for #immutablejs…”

Selectorisi tulisi palauttaa Immutable.JS-objekteja#

Always. Tällä käytännöllä on useita etuja:

  • Se välttää tarpeettomat uudelleenkutsut, jotka johtuvat .toJS():n kutsumisesta selektoreissa (koska .toJS() palauttaa aina uuden objektin).
    • Selektorit, joissa kutsut .toJS():aa, on mahdollista memoida, mutta se on tarpeetonta, kun pelkkä Immutable.js-objektien palauttaminen ilman memoamista riittää.
  • Se luo johdonmukaisen rajapinnan selektoreille; sinun ei tarvitse seurata, palautetaanko Immutable.js-objekti vai tavallinen JavaScript-objekti.

Käytä Immutable.JS-objekteja älykkäissä komponenteissasi#

Älykkäiden komponenttien, jotka pääsevät käsiksi myymälään React Reduxin connect-toiminnon kautta, on käytettävä selektoreidesi palauttamia Immutable.JS-arvoja. Varmista, että vältät mahdolliset ongelmat, joita tämä voi aiheuttaa komponenttien tarpeettoman uudelleen esittämisen vuoksi. Muokkaa selektorit tarvittaessa reselectin kaltaisen kirjaston avulla.

Lisätietoja#

Dokumentaatio

  • Reseptit: Johdettujen tietojen laskeminen
  • FAQ: Immutable Data
  • Reselect Documentation: How do I use Reselect with Immutable.js?

Artikkelit

  • Redux Patterns and Anti-Patterns

Kirjastot

  • Reselect: Selector library for Redux

Älä koskaan käytä toJS() funktiota mapStateToProps#

Immutable.JS-olion muuntaminen JavaScript-olioksi käyttämällä toJS() palauttaa joka kerta uuden olion. Jos teet tämän mapStateToProps:ssä, aiheutat sen, että komponentti luulee objektin muuttuneen joka kerta, kun tilapuu muuttuu, ja käynnistää siten tarpeettoman uudelleenrenderöinnin.

Lisätietoja#

Dokumentaatio

  • FAQ: Immutable Data

Älä koskaan käytä Immutable.JS:ää tyhmissä komponenteissasi#

Tyhmien komponenttiesi tulisi olla puhtaita; eli niiden tulisi tuottaa sama ulostulo samalla syötteellä, eikä niillä tulisi olla ulkoisia riippuvuuksia. Jos annat tällaiselle komponentille Immutable.JS-olion rekvisiittana, teet sen riippuvaiseksi Immutable.JS:stä rekvisiitan arvon poimimisessa ja muussa manipuloinnissa.

Tällainen riippuvuus tekee komponentista epäpuhtaan, vaikeuttaa komponentin testaamista ja tekee komponentin uudelleenkäytöstä ja refaktoroinnista tarpeettoman vaikeaa.

Lisätietoja#

Artikkelit

  • Immutoituvat tietorakenteet ja JavaScript
  • Älykkäät ja tyhmät komponentit Reactissa
  • Vinkkejä parempaan Redux-arkkitehtuuriin: Lessons for Enterprise Scale

Käytä Higher Order Component -komponenttia muuntamaan Smart-komponenttisi Immutable.JS-rekvenssit Dumb-komponenttisi JavaScript-rekvensseiksi#

Jotain täytyy kartoittaa Smart-komponenttisi Immutable.JS-rekvenssit Dumb-komponentissasi käytettäviin puhtaisiin JavaScript-rekvensseihin. Tuo jokin on Higher Order Component (HOC), joka yksinkertaisesti ottaa Immutable.JS-propsit Smart-komponentistasi ja muuntaa ne toJS():n avulla pelkiksi JavaScript-propsiksi, jotka sitten välitetään Dumb-komponentillesi.

Seuraavassa on esimerkki tällaisesta HOC:sta. Samanlainen HOC on saatavilla NPM-pakettina avuksesi: with-immutable-props-to-js.

import React from ’react’
import { Iterable } from ’immutable’
export const toJS = WrappedComponent => wrappedComponentProps => {
const KEY = 0
const VALUE = 1
const propsJS = Object.entries(wrappedComponentProps).reduce(
(newProps, wrappedComponentProp) => {
newProps] = Iterable.isIterable(
wrappedComponentProp
)
? wrappedComponentProp.toJS()
: wrappedComponentProp
return newProps
},
{}
)
return <WrappedComponent {…propsJS} />
}

Copy

Ja näin käyttäisit sitä Smart-komponentissasi:

import { connect } from ’react-redux’
import { toJS } from ’./to-js’

import DumbComponent from ’./dumb.component’
const mapStateToProps = state => {
return {
// obj on Immutable-olio älykkäässä komponentissa, mutta toJS muuntaa sen tavalliseksi
// JavaScript-olioksi ja välittää sen näin ollen DumbComponentille puhtaana JavaScript-oliona
// objektina. Koska se on kuitenkin edelleen Immutable.JS-objekti täällä mapStateToPropsissa,
// ei ole mitään ongelmaa virheellisten uudelleenrenderöintien kanssa.
obj: getImmutableObjectFromStateTree(state)
} }
}
export default connect(mapStateToProps)(toJS(DumbComponent))

Kopioi

Muuntamalla Immutable.JS-objekteja tavallisiksi JavaScript-arvoiksi HOC:n sisällä saavutamme Dumb-komponentin siirrettävyyden, mutta ilman suorituskykyhaittoja, joita aiheutuu toJS():n käyttämisestä älykkäissä komponenteissa.

Huomautus: jos sovelluksesi vaatii korkeaa suoritustehoa, sinun on ehkä vältettävä toJS():aa kokonaan, jolloin joudut käyttämään Immutable.JS:aa Dumb-komponenteissa. Useimmissa sovelluksissa näin ei kuitenkaan ole, ja hyödyt, joita saat pitämällä Immutable.JS:n poissa tyhmistä komponenteistasi (ylläpidettävyys, siirrettävyys ja helpompi testaaminen), ovat paljon suuremmat kuin mahdolliset suorituskykyparannukset, joita sen pitäminen sisällä aiheuttaa.

Lisäksi toJS:n käyttämisen korkeamman järjestyksen komponentissa ei pitäisi aiheuttaa juurikaan suorituskyvyn heikkenemistä, jos sitä lainkaan, koska komponenttia kutsutaan vain silloin, kun liitetyn komponentin rekvisiitta muuttuu. Kuten minkä tahansa suorituskykyongelman kohdalla, suorita ensin suorituskyvyn tarkistukset ennen kuin päätät, mitä optimoida.

Lisätietoja#

Dokumentaatio

  • React: Higher-Order Components

Artikkelit

  • React Higher Order Components in depth

Keskustelut

  • Reddit: acemarke ja cpsubrian kommentit Dan Abramoville: Redux ei ole arkkitehtuuri tai suunnittelumalli, se on vain kirjasto.

Gists

  • cpsubrian: React decorators for redux/react-router/immutable ’smart’ components

Use the Immutable Object Formatter Chrome Extension to Aid Debugging#

Asenna Immutable Object Formatter , ja tarkastele Immutable.JS-tietojasi näkemättä Immutable.JS:n omien objektiominaisuuksien kohinaa.

Vastaa

Sähköpostiosoitettasi ei julkaista.