Použití Immutable.JS s Reduxem#

Obsah#

  • Proč bych měl používat knihovnu zaměřenou na immutable, jako je Immutable.JS?
  • Proč bych měl zvolit Immutable.JS jako immutable knihovnu?
  • Jaké jsou problémy s použitím Immutable.JS?
  • Stojí Immutable.JS za námahu?
  • Jaké jsou osvědčené postupy pro použití Immutable.JS s Reduxem?

Proč bych měl používat knihovnu zaměřenou na immutable, jako je Immutable.JS?#

Knihovny zaměřené na immutable, jako je Immutable.JS, byly navrženy tak, aby překonaly problémy s neměnností, které jsou vlastní jazyku JavaScript, a poskytly všechny výhody neměnnosti s výkonem, který vaše aplikace vyžaduje.

Zda se rozhodnete použít takovou knihovnu, nebo zůstanete u obyčejného JavaScriptu, záleží na tom, nakolik vám vyhovuje přidání další závislosti do vaší aplikace nebo nakolik jste si jisti, že se dokážete vyhnout úskalím, která jsou vlastní přístupu JavaScriptu k neměnnosti.

Ať už se rozhodnete pro kteroukoli možnost, ujistěte se, že jste obeznámeni s koncepty neměnnosti, vedlejších efektů a mutací. Zejména se ujistěte, že dobře rozumíte tomu, co JavaScript dělá při aktualizaci a kopírování hodnot, abyste se ochránili před náhodnými mutacemi, které sníží výkon vaší aplikace nebo ji úplně rozbijí.

Další informace#

Dokumentace

  • Recepty: neměnnost, vedlejší efekty a mutace

Články

  • Úvod do neměnnosti.js a koncepty funkcionálního programování
  • Pro a proti používání neměnnosti s React.js

Proč bych si měl vybrat Immutable.JS jako neměnnou knihovnu?#

Immutable.JS byl navržen tak, aby poskytoval neměnnost výkonným způsobem ve snaze překonat omezení neměnnosti s JavaScriptem. Mezi její hlavní výhody patří:

Zaručená neměnnost#

Data zapouzdřená v objektu Immutable.JS nejsou nikdy mutována. Vždy je vrácena nová kopie. To kontrastuje s JavaScriptem, ve kterém některé operace data nemutují (např. některé metody pole, včetně map, filter, concat, forEach atd.), ale některé ano (pop, push, splice pole atd.).

Bohaté API#

Immutable.JS poskytuje bohatou sadu neměnných objektů pro zapouzdření dat (např.Mapy, seznamy, množiny, záznamy atd.) a rozsáhlou sadu metod pro manipulaci s nimi, včetně metod pro třídění, filtrování a seskupování dat, jejich obrácení, zploštění a vytváření podmnožin.

Výkon#

Immutable.JS dělá spoustu práce v zákulisí, aby optimalizoval výkon. To je klíč k jeho výkonu, protože používání neměnných datových struktur může zahrnovat spoustu nákladného kopírování. Zejména neměnná manipulace s velkými a složitými datovými sadami, jako je například vnořený stavový strom Reduxu, může generovat mnoho mezilehlých kopií objektů, které spotřebovávají paměť a zpomalují výkon, protože sběrač odpadu prohlížeče bojuje o úklid.

Immutable.JS se tomu vyhýbá chytrým sdílením datových struktur pod povrchem, čímž minimalizuje potřebu kopírování dat. Umožňuje také provádět složité řetězce operací bez vytváření zbytečných (a nákladných) klonovaných mezidat, která budou rychle vyhozena.

To samozřejmě nikdy neuvidíte – data, která předáte objektu Immutable.JS, nejsou nikdy mutována. Spíše jsou to mezidata generovaná v rámci Immutable.JS ze zřetězené posloupnosti volání metod, která mohou být volně mutována. Získáte tedy všechny výhody neměnných datových struktur bez (nebo jen s velmi malým) potenciálním zásahem do výkonu.

Další informace#

Články

  • Immutable.js, persistentní datové struktury a sdílení struktur
  • PDF: Jaké jsou problémy s používáním Immutable.JS? #

    Ačkoli je Immutable.JS mocný, je třeba ho používat opatrně, protože s sebou nese vlastní problémy. Všimněte si však, že všechny tyto problémy lze poměrně snadno překonat pečlivým kódováním.

    Obtížná spolupráce s#

    JavaScript neposkytuje neměnné datové struktury. Aby tedy Immutable.JS poskytoval své záruky neměnnosti, musí být vaše data zapouzdřena v objektu Immutable.JS (například Map nebo List atd.). Jakmile jsou tato data takto obsažena, je pro ně obtížné následně spolupracovat s jinými, běžnými objekty JavaScriptu.

    Například již nebude možné odkazovat na vlastnosti objektu prostřednictvím standardní tečkové nebo závorkové notace JavaScriptu. Místo toho se na ně musíte odkazovat prostřednictvím metod get() nebo getIn() souboru Immutable.JS, které používají nepohodlnou syntaxi, jež k vlastnostem přistupuje prostřednictvím pole řetězců, z nichž každý představuje klíč vlastnosti.

    Například místo myObj.prop1.prop2.prop3 byste použili myImmutableMap.getIn().

    To způsobuje nepohodlnou spolupráci nejen s vaším vlastním kódem, ale také s jinými knihovnami, jako je lodash nebo ramda, které očekávají prosté objekty JavaScriptu.

    Všimněte si, že Immutable.JS objekty mají metodu toJS(), která vrací data jako prostou datovou strukturu JavaScriptu, ale tato metoda je extrémně pomalá a její rozsáhlé používání bude negovat výkonnostní výhody, které Immutable.JS poskytuje

    Jakmile jednou použijete Immutable.JS, rozšíří se ve vaší kódové základně#

    Jakmile zapouzdříte data pomocí Immutable.JS, musíte pro přístup k nim použít přístupové prvky vlastností Immutable.JS get() nebo getIn()

    To má za následek rozšíření Immutable.JS po celé vaší kódové základně, včetně potenciálně vašich komponent, kde byste možná raději takové externí závislosti neměli. Celá vaše kódová základna musí vědět, co je a co není objekt Immutable.JS. To také ztěžuje odstranění Immutable.JS z vaší aplikace v budoucnu, pokud byste to někdy potřebovali.

    Tomu problému se lze vyhnout oddělením logiky aplikace od datových struktur, jak je popsáno v části o osvědčených postupech níže.

    Žádné destrukturní nebo rozprostřené operátory#

    Protože musíte přistupovat k datům prostřednictvím Immutable.JS vlastní metody get() a getIn(), nemůžete již používat destrukturovací operátor JavaScriptu (ani navrhovaný operátor Object spread), čímž se váš kód stane rozvláčnějším.

    Nevhodné pro malé hodnoty, které se často mění#

    Immutable.JS funguje nejlépe pro kolekce dat, a čím větší, tím lépe. Může být pomalý, když se vaše data skládají z mnoha malých, jednoduchých objektů JavaScript, z nichž každý obsahuje několik klíčů primitivních hodnot.

    Všimněte si však, že to neplatí pro stavový strom Reduxu, který je (obvykle) reprezentován jako velká kolekce dat.

    Obtížně laditelný#

    Immutable.JS objekty, jako jsou Map, List apod, mohou být obtížně laditelné, protože kontrola takového objektu odhalí celou vnořenou hierarchii vlastností specifických pro Immutable.JS, které vás nezajímají, zatímco vaše skutečná data, která vás zajímají, jsou zapouzdřena několik vrstev hluboko.

    Pro vyřešení tohoto problému použijte rozšíření prohlížeče, například Immutable.js Object Formatter, které v nástroji Chrome Dev Tools zobrazí vaše data a při kontrole dat skryje vlastnosti Immutable.JS.

    Porušuje odkazy na objekty, což způsobuje nízký výkon#

    Jednou z klíčových výhod neměnnosti je, že umožňuje mělkou kontrolu rovnosti, což výrazně zlepšuje výkon.

    Pokud dvě různé proměnné odkazují na stejný neměnný objekt, pak stačí jednoduchá kontrola rovnosti obou proměnných, aby se zjistilo, že jsou si rovny a že objekt, na který obě odkazují, se nezměnil. Kontrola rovnosti nikdy nemusí kontrolovat hodnoty žádné z vlastností objektu, protože ten je samozřejmě neměnný.

    Mělká kontrola však nebude fungovat, pokud jsou vaše data zapouzdřená v objektu Immutable.JS sama o sobě objektem. Je to proto, že metoda Immutable.JS toJS(), která vrací data obsažená v objektu Immutable.JS jako hodnotu JavaScriptu, vytvoří při každém svém volání nový objekt, a tak přeruší odkaz se zapouzdřenými daty.

    Příklad dvojí volání metody toJS() a přiřazení výsledku dvěma různým proměnným způsobí selhání kontroly rovnosti těchto dvou proměnných, i když se samotné hodnoty objektů nezměnily.

    Tento problém nastane zejména v případě, že metodu toJS() použijete ve funkci mapStateToProps zabalené komponenty, protože React-Redux mělce porovnává každou hodnotu ve vráceném objektu props. Například hodnota, na kterou odkazuje todos prop vrácený z mapStateToProps níže, bude vždy jiný objekt, a proto neprojde mělkou kontrolou rovnosti.

    // AVOID .toJS() v mapStateToProps
    function mapStateToProps(state) {
    return {
    todos: state.get(‚todos‘).toJS() // Vždy nový objekt
    }
    }

    Kopírovat

    Pokud mělká kontrola selže, React-Redux způsobí opětovné vykreslení komponenty. Použití toJS() v mapStateToProps tímto způsobem tedy vždy způsobí opětovné vykreslení komponenty, i když se hodnota nikdy nezmění, což má velký dopad na výkon.

    Tomu lze zabránit použitím toJS() v komponentě vyššího řádu, jak je popsáno v části Nejlepší postupy níže.

    Další informace#

    Články

    • Immutable.js, perzistentní datové struktury a sdílení struktur
    • Immutable Data Structures and JavaScript
    • React.js pure render performance anti-pattern
    • Building Efficient UI with React and Redux

    Chrome Extension

    • Immutable Object Formatter

    Stojí používání Immutable.JS za námahu? #

    Často ano. Je třeba zvážit různé kompromisy a názory, ale existuje mnoho dobrých důvodů, proč Immutable.JS používat. Nepodceňujte obtížnost snahy vystopovat vlastnost stromu stavů, která byla neúmyslně zmutována.

    Komponenty se jednak znovu vykreslují, i když by se vykreslovat neměly, jednak se odmítají vykreslovat, i když by se vykreslovat měly, a vystopovat chybu způsobující problém s vykreslováním je obtížné, protože nesprávně vykreslovaná komponenta nemusí být nutně ta, jejíž vlastnosti byly omylem zmutovány.

    Tento problém je způsoben převážně vracením zmutovaného objektu stavu z reduktoru Redux. S Immutable.JS tento problém jednoduše neexistuje, čímž z vaší aplikace odstraníte celou třídu chyb.

    To je spolu s jeho výkonem a bohatým API pro manipulaci s daty důvod, proč se Immutable.JS vyplatí.

    Další informace#

    Dokumentace

    • Řešení problémů: Při odeslání akce se nic nestane

    Jaké jsou některé názorové osvědčené postupy pro použití Immutable.JS s Reduxem?#

    Immutable.JS může vaší aplikaci přinést výrazné zlepšení spolehlivosti a výkonu, ale musí se správně používat. Pokud se rozhodnete Immutable.JS používat (a nezapomeňte, že to není nutné a že existují i jiné immutable knihovny, které můžete použít), dodržujte tyto názorově shodné osvědčené postupy a budete z něj moci vytěžit maximum, aniž byste narazili na některý z problémů, které může potenciálně způsobit.

    Nikdy nemíchejte běžné objekty JavaScriptu s Immutable.JS#

    Nikdy nedovolte, aby běžný objekt JavaScriptu obsahoval vlastnosti Immutable.JS. Stejně tak nikdy nedovolte, aby objekt Immutable.JS obsahoval prostý objekt JavaScriptu.

    Další informace#

    Články

    • Immutable Data Structures and JavaScript

    Vytvořte celý stavový strom Reduxu jako Immutable.JS#

    Pro aplikaci Redux by celý váš stavový strom měl být objektem Immutable.JS a vůbec nepoužívejte žádné obyčejné objekty JavaScriptu.

    • Vytvořte strom pomocí funkce Immutable.JS fromJS().

    • Použijte Immutable.JS-aware verzi funkce combineReducers, například tu v redux-immutable, protože Redux sám očekává, že stavový strom bude prostým objektem JavaScriptu.

    • Při přidávání objektů JavaScriptu do mapy nebo seznamu Immutable.JS pomocí Immutable.JS metodami update, merge nebo set, zajistěte, aby byl přidávaný objekt nejprve převeden na objekt Immutable pomocí fromJS().

    Příklad

    // vyhněte se
    const newObj = { key: value }
    const newState = state.setIn(, newObj)
    // newObj byl přidán jako prostý JavaScriptový objekt, NE jako Immutable.JS Map
    // doporučeno
    const newObj = { key: value }
    const newState = state.setIn(, fromJS(newObj))
    // newObj je nyní Immutable.JS Map

    Kopírovat

    Další informace#

    Články

    • Immutable Data Structures and JavaScript

    Knihovny

    • redux-immutable

    Použít Immutable.JS všude kromě hloupých komponent#

    Používání Immutable.JS všude udržuje výkonnost vašeho kódu. Používejte jej ve svých chytrých komponentách, selektoru, sázích nebo thuncích, tvůrcích akcí a zejména v reduktorech.

    Nepoužívejte však Immutable.JS ve svých hloupých komponentách.

    Další informace#

    Články

    • Immutable Data Structures and JavaScript
    • Chytré a hloupé komponenty v Reactu

    Omezte používání toJS()#

    toJS() je drahá funkce a popírá účel použití Immutable.JS. Vyhněte se jejímu používání.

    Další informace#

    Diskuse

    • Lee Byron na Twitteru: „Perf tip for #immutablejs…“

    Vaše selektory by měly vracet objekty Immutable.JS#

    Vždy. Tento postup má několik výhod:

    • Předchází zbytečnému opakování volání .toJS() v selektoru (protože .toJS() vždy vrátí nový objekt).
      • Je možné memoizovat selektory, ve kterých voláte .toJS(), ale je to zbytečné, když stačí vracet objekty Immutable.js bez memoizace.
    • Vytváří konzistentní rozhraní pro selektory; nebudete muset sledovat, zda bude vrácen objekt Immutable.js nebo obyčejný objekt JavaScriptu.

    Používejte objekty Immutable.JS ve svých inteligentních komponentách#

    Chytré komponenty, které přistupují k úložišti prostřednictvím funkce connect React Redux, musí používat hodnoty Immutable.JS vrácené vašimi selektory. Ujistěte se, že se vyhnete možným problémům, které může způsobit zbytečné překreslování komponent. V případě potřeby si selektory zapamatujte pomocí knihovny, například reselect.

    Další informace#

    Dokumentace

    • Recepty: Výpočet odvozených dat
    • FAQ: Dokumentace k výběru: Neměnná data
    • Dokumentace k výběru:

    Články

    • Redux Patterns and Anti-Patterns

    Knihovny

    • Reselect: Reselect: knihovna selektorů pro Redux

    Nikdy nepoužívejte toJS() v mapStateToProps#

    Konverze objektu Immutable.JS na objekt JavaScript pomocí toJS() vrátí pokaždé nový objekt. Pokud to provedete v mapStateToProps, způsobíte, že se komponenta bude domnívat, že se objekt změnil při každé změně stromu stavů, a vyvoláte tak zbytečné opětovné vykreslení.

    Další informace#

    Dokumentace

    • FAQ: JS v hloupých komponentách#

      Vaše hloupé komponenty by měly být čisté, to znamená, že by měly produkovat stejný výstup při stejném vstupu a neměly by mít žádné vnější závislosti. Pokud takové komponentě předáte objekt Immutable.JS jako rekvizitu, učiníte ji závislou na Immutable.JS při získávání hodnoty rekvizity a jiné manipulaci s ní.

      Taková závislost činí komponentu nečistou, ztěžuje testování komponenty a zbytečně ztěžuje její opětovné použití a refaktorizaci.

      Další informace#

      Články

      • Immutable Data Structures and JavaScript
      • Chytré a hloupé komponenty v Reactu
      • Tipy pro lepší architekturu Redux: Poučení pro podnikové měřítko

      K převodu rekvizit Immutable.JS vaší inteligentní komponenty na rekvizity JavaScriptu vaší hloupé komponenty použijte komponentu vyššího řádu#

      Něco musí mapovat rekvizity Immutable.JS ve vaší inteligentní komponentě na rekvizity čistého JavaScriptu použité ve vaší hloupé komponentě. Tím něčím je komponenta vyššího řádu (HOC), která jednoduše převezme rekvizity Immutable.JS z vaší Chytré komponenty a převede je pomocí toJS() na čisté rekvizity JavaScriptu, které pak předá vaší Hloupé komponentě.

      Příklad takové HOC následuje. Podobný HOC je pro vaše pohodlí k dispozici jako balíček NPM: 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

      A takto byste to použili ve své inteligentní komponentě:

      import { connect } from ‚react-redux‘
      import { toJS } from ‚./to-js‘
      import DumbComponent from ‚./dumb.component‘
      const mapStateToProps = state => {
      return {
      // obj je Immutable objekt v Smart Component, ale toJS ho převede na čistý
      // JavaScript objekt, a tak ho předá DumbComponent jako čistý JavaScript
      // objekt. Protože se však zde v mapStateToProps stále jedná o objekt Immutable.JS,
      // nevzniká problém s chybným opětovným vykreslením.
      obj: getImmutableObjectFromStateTree(state)
      }
      }
      export default connect(mapStateToProps)(toJS(DumbComponent))

      Kopírovat

      Převedením objektů Immutable.JS na obyčejné hodnoty JavaScriptu v rámci HOC dosáhneme přenositelnosti Dumb Component, ale bez výkonnostních zásahů použití toJS() v Smart Component.

      Poznámka: pokud vaše aplikace vyžaduje vysoký výkon, možná se budete muset toJS() úplně vyhnout, a tak budete muset v dumb komponentách používat Immutable.JS. Pro většinu aplikací to však nebude tento případ a výhody ponechání Immutable.JS mimo vaše hloupé komponenty (udržovatelnost, přenositelnost a snazší testování) budou daleko převažovat nad jakýmkoli domnělým zlepšením výkonu při jeho ponechání v komponentě.

      Použití toJS v komponentě vyššího řádu by navíc nemělo způsobit velké, pokud vůbec nějaké, zhoršení výkonu, protože komponenta bude volána pouze při změně rekvizit připojené komponenty. Stejně jako v případě jakéhokoli problému s výkonem proveďte nejprve kontrolu výkonu, než se rozhodnete, co optimalizovat.

      Další informace#

      Dokumentace

      • React: Komponenty vyššího řádu

      Články

      • React Komponenty vyššího řádu do hloubky

      Diskuze

      • Reddit: acemarke a cpsubrian komentují Dan Abramov: Redux není architektura ani návrhový vzor, je to jen knihovna

      Gists

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

      Pomocí rozšíření Immutable Object Formatter pro Chrome usnadníte ladění#

      Nainstalujte si Immutable Object Formatter , a kontrolujte data Immutable.JS, aniž byste viděli šum vlastních vlastností objektů Immutable.JS.

      .

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.