Het gebruik van Immutable.JS met Redux#

Inhoudsopgave#

  • Waarom zou ik een op immutable gerichte library zoals Immutable.JS moeten gebruiken?
  • Waarom zou ik Immutable.JS als immutable library moeten kiezen?
  • Wat zijn de problemen met het gebruik van Immutable.JS?
  • Is Immutable.JS de moeite waard?
  • Wat zijn een aantal aanbevolen Best Practices voor het gebruik van Immutable.JS met Redux?

Waarom zou ik een immutable-focused library zoals Immutable.JS gebruiken?#

Immutable-focused libraries zoals Immutable.JS zijn ontworpen om de problemen met onveranderlijkheid die inherent zijn aan JavaScript te overwinnen, en bieden alle voordelen van onveranderlijkheid met de prestaties die uw app nodig heeft.

Of je ervoor kiest om zo’n bibliotheek te gebruiken, of gewoon JavaScript, hangt af van hoe comfortabel je bent met het toevoegen van nog een afhankelijkheid aan je app, of hoe zeker je bent dat je de valkuilen kunt vermijden die inherent zijn aan JavaScript’s benadering van onveranderlijkheid.

Welke optie je ook kiest, zorg ervoor dat je bekend bent met de concepten van onveranderlijkheid, neveneffecten en mutatie. Zorg er vooral voor dat u goed begrijpt wat JavaScript doet bij het bijwerken en kopiëren van waarden, zodat u zich kunt wapenen tegen toevallige mutaties die de prestaties van uw app verslechteren of zelfs helemaal kapotmaken.

Volgende informatie#

Documentatie

  • Recipes: onveranderlijkheid, neveneffecten en mutatie

Artikels

  • Inleiding tot Immutable.js and Functional Programming Concepts
  • Pros and Cons of using immutability with React.js

Why should I choose Immutable.JS as an immutable library?#

Immutable.JS is ontworpen om onveranderlijkheid te bieden op een performante manier in een poging om de beperkingen van onveranderlijkheid met JavaScript te overwinnen. De belangrijkste voordelen zijn:

Gegarandeerde onveranderlijkheid#

Gegevens die zijn ingekapseld in een Immutable.JS object worden nooit gemuteerd. Een nieuwe kopie wordt altijd geretourneerd. Dit in tegenstelling tot JavaScript, waarin sommige bewerkingen je gegevens niet muteren (bijv. sommige Array-methoden, waaronder map, filter, concat, forEach, enz.), maar sommige wel (Array’s pop, push, splice, enz.).

Rijke API#

Immutable.JS biedt een rijke set van onveranderlijke objecten om je gegevens in te kapselen (bijv.b.v. Maps, Lists, Sets, Records, etc.), en een uitgebreide set van methoden om deze te manipuleren, inclusief methoden om de gegevens te sorteren, filteren en groeperen, om te keren, af te vlakken, en subsets te maken.

Performance#

Immutable.JS doet veel werk achter de schermen om de prestaties te optimaliseren. Dit is de sleutel tot zijn kracht, omdat het gebruik van onveranderlijke gegevensstructuren veel duur kopieerwerk met zich mee kan brengen. In het bijzonder, het onveranderlijk manipuleren van grote, complexe gegevensverzamelingen, zoals een geneste Redux state tree, kan veel tussenliggende kopieën van objecten genereren, die geheugen verbruiken en de prestaties vertragen als de garbage collector van de browser vecht om dingen op te ruimen.

Immutable.JS vermijdt dit door het slim delen van gegevensstructuren onder de oppervlakte, waardoor de noodzaak om gegevens te kopiëren wordt geminimaliseerd. Het maakt het ook mogelijk complexe ketens van bewerkingen uit te voeren zonder onnodige (en kostbare) gekloonde tussenliggende gegevens te maken die snel worden weggegooid.

Je ziet dit natuurlijk nooit – de gegevens die je aan een Immutable.JS-object geeft, worden nooit gemuteerd. In plaats daarvan zijn het de tussenliggende gegevens die binnen Immutable.JS worden gegenereerd uit een aaneenschakeling van methode-aanroepen die vrij zijn om te worden gemuteerd. U krijgt dus alle voordelen van onveranderlijke gegevensstructuren zonder (of zeer weinig) van de potentiële prestatieshits.

Nadere informatie#

Artikelen

  • Immutable.js, persistente gegevensstructuren en structureel delen
  • PDF: JavaScript Immutability – Don’t go changing

Libraries

  • Immutable.js

Wat zijn de problemen bij het gebruik van Immutable.JS?#

Hoewel het krachtig is, moet Immutable.JS voorzichtig worden gebruikt, want het heeft zo zijn eigen problemen. Merk echter op dat al deze problemen vrij eenvoudig kunnen worden opgelost met zorgvuldige codering.

Moeilijk om mee samen te werken#

JavaScript biedt geen onveranderlijke gegevensstructuren. Om de Immutable.JS-garanties te kunnen bieden, moeten de gegevens worden ingekapseld in een Immutable.JS-object (zoals een Map of een List, enz.). Zodra het op deze manier is ingekapseld, is het moeilijk voor die gegevens om vervolgens samen te werken met andere, gewone JavaScript-objecten.

U zult bijvoorbeeld niet langer in staat zijn om naar de eigenschappen van een object te verwijzen via standaard JavaScript punt- of haakjesnotatie. In plaats daarvan moet u ernaar verwijzen via de methoden get() of getIn() van Immutable.JS, die een onhandige syntaxis gebruiken die toegang biedt tot eigenschappen via een array van tekenreeksen, waarvan elk een eigenschappensleutel vertegenwoordigt.

Bij voorbeeld, in plaats van myObj.prop1.prop2.prop3, zou u myImmutableMap.getIn() gebruiken.

Dit maakt het onhandig om niet alleen met uw eigen code samen te werken, maar ook met andere bibliotheken, zoals lodash of ramda, die gewone JavaScript-objecten verwachten.

Merk op dat Immutable.JS-objecten wel een toJS()-methode hebben, die de gegevens retourneert als een gewone JavaScript-gegevensstructuur, maar deze methode is extreem traag, en als u deze op grote schaal gebruikt, worden de prestatievoordelen die Immutable.JS biedt tenietgedaan

Eenmaal gebruikt, zal Immutable.JS zich door uw hele codebase verspreiden#

Nadat u uw gegevens inkapselt met Immutable.JS, moet u Immutable.JS’s get() of getIn() property accessors gebruiken om er toegang toe te krijgen.

Dit heeft tot gevolg dat Immutable.JS over uw hele codebase wordt verspreid, inclusief mogelijk uw componenten, waar u misschien liever niet zulke externe afhankelijkheden wilt hebben. Uw hele codebase moet weten wat een Immutable.JS object is, en wat niet. Het maakt het ook moeilijk om Immutable.JS in de toekomst uit uw app te verwijderen, mocht dat ooit nodig zijn.

Dit probleem kan worden vermeden door uw applicatielogica los te koppelen van uw gegevensstructuren, zoals uiteengezet in de best practices-sectie hieronder.

Geen Destructuring of Spread Operators#

Omdat u toegang moet krijgen tot uw gegevens via Immutable.JS’s eigen get() en getIn() methoden, kunt u niet langer gebruik maken van JavaScript’s destructuring operator (of de voorgestelde Object spread operator), waardoor uw code meer verbose.

Niet geschikt voor kleine waarden die vaak veranderen#

Immutable.JS werkt het beste voor verzamelingen van gegevens, en hoe groter hoe beter. Het kan traag zijn wanneer je gegevens bestaan uit veel kleine, eenvoudige JavaScript-objecten, met elk een paar sleutels van primitieve waarden.

Merk echter op dat dit niet van toepassing is op de Redux state tree, die (meestal) wordt weergegeven als een grote verzameling gegevens.

Moeilijk te debuggen#

Immutable.JS-objecten, zoals Map, List, etc., kunnen moeilijk te debuggen zijn, omdat de inspectie van een dergelijk object een hele hiërarchie van Immutable.JS-specifieke eigenschappen onthult die u niet belangrijk vindt, terwijl uw eigenlijke gegevens die u wel belangrijk vindt, meerdere lagen diep zijn ingekapseld.

Om dit probleem op te lossen, gebruikt u een browserextensie zoals de Immutable.js Object Formatter, die uw gegevens weergeeft in Chrome Dev Tools, en de eigenschappen van Immutable.JS verbergt bij het inspecteren van uw gegevens.

Breekt objectverwijzingen, waardoor slechte prestaties ontstaan#

Eén van de belangrijkste voordelen van onveranderlijkheid is dat het ondiepe gelijkheidscontroles mogelijk maakt, wat de prestaties drastisch verbetert.

Als twee verschillende variabelen naar hetzelfde onveranderlijke object verwijzen, dan is een eenvoudige gelijkheidscontrole van de twee variabelen voldoende om vast te stellen dat ze gelijk zijn, en dat het object waar ze beide naar verwijzen ongewijzigd is gebleven. De gelijkheidscontrole hoeft nooit de waarden van de eigenschappen van het object te controleren, omdat het natuurlijk onveranderlijk is.

De ondiepe controle zal echter niet werken als je gegevens die zijn ingekapseld in een Immutable.JS object zelf een object is. Dit komt omdat Immutable.JS’s toJS() methode, die de gegevens in een Immutable.JS-object retourneert als een JavaScript-waarde, een nieuw object zal maken elke keer dat het wordt aangeroepen, en dus de referentie met de ingekapselde gegevens zal breken.

Dus, toJS() twee keer aanroepen, bijvoorbeeld, en het resultaat toewijzen aan twee verschillende variabelen zal een gelijkheidscontrole op die twee variabelen doen mislukken, ook al zijn de objectwaarden zelf niet veranderd.

Dit is een bijzonder probleem als u toJS() gebruikt in de mapStateToProps-functie van een verpakt component, omdat React-Redux elke waarde in het geretourneerde props-object oppervlakkig vergelijkt. Bijvoorbeeld, de waarde waarnaar verwezen wordt door de todos prop geretourneerd door mapStateToProps hieronder zal altijd een ander object zijn, en zal dus een ondiepe gelijkheidscontrole niet doorstaan.

// AVOID .toJS() in mapStateToProps
function mapStateToProps(state) {
return {
todos: state.get(’todos’).toJS() // Altijd een nieuw object
}
}

Copy

Wanneer de ondiepe controle mislukt, zorgt React-Redux ervoor dat de component opnieuw wordt gerenderd. Als toJS() op deze manier in mapStateToProps wordt gebruikt, zal de component dus altijd opnieuw worden gerenderd, zelfs als de waarde nooit verandert, wat een grote impact heeft op de prestaties.

Dit kan worden voorkomen door toJS() te gebruiken in een Higher Order Component, zoals wordt besproken in de sectie Best Practices hieronder.

Nadere informatie#

Artikels

  • Immutable.js, persistente datastructuren en structureel delen
  • Immutable Data Structures and JavaScript
  • React.js pure render performance anti-pattern
  • Building Efficient UI with React and Redux

Chrome Extension

  • Immutable Object Formatter

Is het gebruik van Immutable.JS de moeite waard?#

Vaak wel, ja. Er zijn verschillende afwegingen en meningen die in overweging moeten worden genomen, maar er zijn veel goede redenen om Immutable.JS te gebruiken. Onderschat niet de moeilijkheid van het proberen op te sporen van een eigenschap van je state tree die per ongeluk is gemuteerd.

Componenten zullen zowel opnieuw renderen wanneer ze dat niet zouden moeten doen, als weigeren te renderen wanneer ze dat wel zouden moeten doen, en het opsporen van de bug die het renderprobleem veroorzaakt is moeilijk, omdat de component die verkeerd rendert niet noodzakelijk degene is wiens eigenschappen per ongeluk worden gemuteerd.

Dit probleem wordt voornamelijk veroorzaakt door het retourneren van een gemuteerd state-object van een Redux reducer. Met Immutable.JS bestaat dit probleem gewoon niet, waardoor een hele klasse van bugs uit uw app wordt verwijderd.

Dit, samen met de prestaties en de rijke API voor gegevensmanipulatie, is waarom Immutable.JS de moeite waard is.

Nadere informatie#

Documentatie

  • Problemen oplossen: Er gebeurt niets als ik een actie dispatch

Wat zijn volgens u de beste praktijken voor het gebruik van Immutable.JS met Redux? #

Immutable.JS kan aanzienlijke verbeteringen opleveren voor de betrouwbaarheid en prestaties van uw app, maar het moet wel correct worden gebruikt. Als je ervoor kiest om Immutable.JS te gebruiken (en onthoud, je bent niet verplicht om dat te doen, en er zijn andere immutable bibliotheken die je kunt gebruiken), volg dan deze aanbevolen best practices, en je zult in staat zijn om er het meeste uit te halen, zonder te struikelen over de problemen die het mogelijk kan veroorzaken.

Meng nooit gewone JavaScript-objecten met Immutable.JS#

Laat nooit een gewoon JavaScript-object Immutable.JS eigenschappen bevatten. Laat evenmin een Immutable.JS object een gewoon JavaScript object bevatten.

Nadere informatie#

Artikelen

  • Immutable Data Structures and JavaScript

Maak van uw gehele Redux state tree een Immutable.JS-object#

Voor een Redux-app moet uw volledige state tree een Immutable.JS-object zijn, waarbij helemaal geen gewone JavaScript-objecten worden gebruikt.

  • Maak de boom met behulp van de fromJS() functie van Immutable.JS.

  • Gebruik een Immutable.JS-bewuste versie van de functie combineReducers, zoals die in redux-immutable, aangezien Redux zelf verwacht dat de boomstructuur een gewoon JavaScript-object is.

  • Wanneer u JavaScript-objecten toevoegt aan een Immutable.JS-map of -lijst met behulp van Immutable.JS’s update, merge of setmethoden, moet u ervoor zorgen dat het object dat wordt toegevoegd eerst wordt geconverteerd naar een Immutable-object met behulp van fromJS().

Example

//
const newObj = { key: value }
const newState = state.setIn(, newObj)
// newObj is toegevoegd als een gewoon JavaScript-object, NIET als een Immutable.JS Map
// aanbevolen
const newObj = { key: value }
const newState = state.setIn(, fromJS(newObj))
// newObj is nu een Immutable.JS Map

Copy

Nadere informatie#

Artikelen

  • Immutable Data Structures and JavaScript

Libraries

  • redux-immutable

Gebruik Immutable.JS overal behalve in je domme componenten#

Door Immutable.JS overal te gebruiken, blijft je code performant. Gebruik het in je slimme componenten, je selectors, je sagas of thunks, action creators, en vooral je reducers.

Gebruik echter geen Immutable.JS in je domme componenten.

Nadere informatie#

Artikelen

  • Immutable Data Structures and JavaScript
  • Smart and Dumb Components in React

Beperk uw gebruik van toJS()#

toJS() is een dure functie en ontkracht het doel van het gebruik van Immutable.JS. Vermijd het gebruik ervan.

Nadere informatie#

Discussies

  • Lee Byron op Twitter: “Perf tip voor #immutablejs…”

Je selectors moeten altijd onveranderlijke.JS-objecten terugsturen#

Altijd. Dit heeft verschillende voordelen:

  • Het voorkomt onnodige herhalingen die worden veroorzaakt door het aanroepen van .toJS() in selectors (aangezien .toJS() altijd een nieuw object zal retourneren).
    • Het is mogelijk om selectors te memoïseren waar u .toJS() aanroept, maar dit is overbodig wanneer het retourneren van Immutable.js-objecten zonder memoïseren voldoende is.
  • Het zorgt voor een consistente interface voor selectors; u hoeft niet bij te houden of een Immutable.js-object of een gewoon JavaScript-object wordt geretourneerd.

Gebruik Immutable.JS-objecten in uw Smart Components#

Smart components die toegang hebben tot de winkel via de connect-functie van React Redux, moeten de Immutable.JS-waarden gebruiken die door uw selectors worden geretourneerd. Zorg ervoor dat je de potentiële problemen vermijdt die dit kan veroorzaken met onnodige component re-rendering. Memoize uw selectors met behulp van een bibliotheek zoals reselect indien nodig.

Volgende informatie#

Documentatie

  • Recipes: Afgeleide gegevens berekenen
  • FAQ: Immutable Data
  • Reselect Documentatie: Hoe gebruik ik Reselect met Immutable.js?

Artikelen

  • Redux Patterns and Anti-Patterns

Libraries

  • Reselect: Selector-bibliotheek voor Redux

Gebruik nooit toJS() in mapStateToProps#

Het converteren van een Immutable.JS-object naar een JavaScript-object met toJS() zal telkens een nieuw object opleveren. Als je dit in mapStateToProps doet, zal de component denken dat het object is veranderd elke keer als de state tree verandert, en dus een onnodige re-render veroorzaken.

Volgende informatie#

Documentatie

  • FAQ: Immutable Data

Gebruik nooit Immutable.JS in uw domme componenten#

Uw domme componenten moeten zuiver zijn; dat wil zeggen dat ze dezelfde uitvoer moeten produceren bij dezelfde invoer en geen externe afhankelijkheden mogen hebben. Als je zo’n component een Immutable.JS object als prop meegeeft, maak je het afhankelijk van Immutable.JS om de waarde van de prop te extraheren en anderszins te manipuleren.

Zo’n afhankelijkheid maakt de component onzuiver, maakt het testen van de component moeilijker, en maakt het hergebruiken en refactoren van de component onnodig moeilijk.

Nadere informatie#

Artikels

  • Immutable Data Structures and JavaScript
  • Smart and Dumb Components in React
  • Tips For a Better Redux Architecture: Lessons for Enterprise Scale

Gebruik een Higher Order Component om de Immutable.JS props van je Smart Component om te zetten naar de JavaScript props van je Dumb Component#

Er moet iets zijn om de Immutable.JS props in je Smart Component in kaart te brengen naar de pure JavaScript props die in je Dumb Component worden gebruikt. Dat iets is een Higher Order Component (HOC) die eenvoudigweg de Immutable.JS props van uw Smart Component neemt, en ze converteert met behulp van toJS() naar pure JavaScript props, die vervolgens worden doorgegeven aan uw Dumb Component.

Een voorbeeld van zo’n HOC volgt hieronder. Een soortgelijke HOC is beschikbaar als een NPM-pakket voor uw gemak: with-immutable-props-to-js.

importeer React van ‘react’
importeer { Iterable } van ‘immutable’
exporteer 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

En dit is hoe u het in uw Smart Component zou gebruiken:

import {connect } from ‘react-redux’
import { toJS } from ‘./to-js’
import DumbComponent from ‘./dumb.component’
const mapStateToProps = state => {
return {
// obj is een Immutable-object in Smart Component, maar het wordt door toJS geconverteerd naar een gewoon
JavaScript-object, en dus als een zuiver JavaScript
// object aan DumbComponent doorgegeven. Omdat het echter nog steeds een Immutable.JS-object is in mapStateToProps,
// is er geen probleem met foutieve re-renderings.
obj: getImmutableObjectFromStateTree(state)
}
}
export default connect(mapStateToProps)(toJS(DumbComponent))

Copy

Door Immutable.JS-objecten te converteren naar gewone JavaScript-waarden binnen een HOC, bereiken we overdraagbaarheid van Dumb Components, maar zonder de prestatiehits van het gebruik van toJS() in de Smart Component.

Note: als uw app hoge prestaties vereist, moet u toJS() misschien helemaal vermijden, en zult u dus Immutable.JS moeten gebruiken in uw Dumb Components. Voor de meeste apps zal dit echter niet het geval zijn, en de voordelen van het weglaten van Immutable.JS uit je domme componenten (onderhoudbaarheid, portabiliteit en eenvoudiger testen) zullen veel groter zijn dan de waargenomen prestatieverbeteringen van het weglaten ervan.

Daarnaast zou het gebruik van toJS in een Higher Order Component niet veel of geen prestatievermindering moeten veroorzaken, omdat de component alleen zal worden aangeroepen wanneer de props van de aangesloten component veranderen. Zoals met elk prestatie probleem, voer eerst prestatie controles uit alvorens te beslissen wat te optimaliseren.

Volgende informatie#

Documentatie

  • React: Higher-Order Components

Artikels

  • React Higher Order Components in de diepte

Discussies

  • Reddit: acemarke en cpsubrian geven commentaar op Dan Abramov: Redux is geen architectuur of ontwerppatroon, het is slechts een bibliotheek.

Gists

  • cpsubrian: React-decoratoren voor redux/react-router/immutable ‘slimme’ componenten

Gebruik de Immutable Object Formatter Chrome-extensie als hulp bij het debuggen#

Installeer de Immutable Object Formatter , en inspecteer uw Immutable.JS-gegevens zonder de ruis van de eigen objecteigenschappen van Immutable.JS te zien.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.