diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..67e9b093 --- /dev/null +++ b/404.html @@ -0,0 +1,26 @@ + + + + + +Page Not Found | Immer + + + + + + + + + + + + + + +
+
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + + + \ No newline at end of file diff --git a/api/index.html b/api/index.html new file mode 100644 index 00000000..8649fa23 --- /dev/null +++ b/api/index.html @@ -0,0 +1,26 @@ + + + + + +API overview | Immer + + + + + + + + + + + + + + +
+
Skip to main content

API overview

Exported nameDescriptionSection
produceThe core API of Immer: import {produce} from "immer"Produce
applyPatchesGiven a base state or draft, and a set of patches, applies the patchesPatches
castDraftConverts any immutable type to its mutable counterpart. This is just a cast and doesn't actually do anything.TypeScript
castImmutableConverts any mutable type to its immutable counterpart. This is just a cast and doesn't actually do anything.TypeScript
createDraftGiven a base state, creates a mutable draft for which any modifications will be recordedAsync
currentGiven a draft object (doesn't have to be a tree root), takes a snapshot of the current state of the draftCurrent
Draft<T>Exposed TypeScript type to convert an immutable type to a mutable typeTypeScript
enableMapSet()Enables support for Map and Set collections.Installation
enablePatches()Enables support for JSON patches.Installation
finishDraftGiven an draft created using createDraft, seals the draft and produces and returns the next immutable state that captures all the changesAsync
freeze(obj, deep?)Freezes draftable objects. Returns the original object. By default freezes shallowly, but if the second argument is true it will freeze recursively.
Immerconstructor that can be used to create a second "immer" instance (exposing all APIs listed in this instance), that doesn't share its settings with global instance.
immerableSymbol that can be added to a constructor or prototype, to indicate that Immer should treat the class as something that can be safely draftedClasses
Immutable<T>Exposed TypeScript type to convert mutable types to immutable types
isDraftReturns true if the given object is a draft object
isDraftableReturns true if Immer is capable of turning this object into a draft. Which is true for: arrays, objects without prototype, objects with Object as their prototype, objects that have the immerable symbol on their constructor or prototype
nothingValue that can be returned from a recipe, to indicate that the value undefined should be producedReturn
originalGiven a draft object (doesn't have to be a tree root), returns the original object at the same path in the original state tree, if presentOriginal
PatchExposed TypeScript type, describes the shape of an (inverse) patch objectPatches
produceWithPatchesWorks the same as produce, but instead of just returning the produced object, it returns a tuple, consisting of [result, patches, inversePatches].Patches
setAutoFreezeEnables / disables automatic freezing of the trees produces. By default enabled.Freezing
setUseStrictShallowCopyCan be used to enable strict shallow copy. If enable, immer copies non-enumerable properties as much as possible.Classes

Importing immer

In most cases, the only thing you need to import from Immer is produce:

import {produce} from "immer"

Note that in older versions, produce was also available as default export (e.g. import produce from "immer" was also valid, but that is no longer the case to improve eco system compatibility.

+ + + + \ No newline at end of file diff --git a/assets/css/styles.d8d8e956.css b/assets/css/styles.d8d8e956.css new file mode 100644 index 00000000..f859c0e0 --- /dev/null +++ b/assets/css/styles.d8d8e956.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:transparent;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:rgba(0,0,0,.05);--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 rgba(0,0,0,.1);--ifm-global-shadow-md:0 5px 40px rgba(0,0,0,.2);--ifm-global-shadow-tl:0 12px 28px 0 rgba(0,0,0,.2),0 2px 4px 0 rgba(0,0,0,.1);--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:transparent;--ifm-table-stripe-background:rgba(0,0,0,.03);--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:transparent}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid rgba(0,0,0,.1);border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:transparent;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c200c2}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:rgba(53,120,229,.15);--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:rgba(235,237,240,.15);--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:rgba(0,164,0,.15);--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:rgba(84,199,236,.15);--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:rgba(255,186,0,.15);--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:rgba(250,56,62,.15);--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{-moz-column-gap:var(--ifm-avatar-intro-margin);column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs__link:-moz-any-link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs__link:any-link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:transparent;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.content_knG7 a,a:hover{text-decoration:underline}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor transparent;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:hsla(0,0%,100%,.1);--ifm-navbar-search-input-placeholder-color:hsla(0,0%,100%,.5);color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:hsla(0,0%,100%,.05);--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::-moz-placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:rgba(0,0,0,.6);right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{-moz-column-gap:var(--ifm-pagination-page-spacing);column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.tocCollapsibleContent_vkbj a,details a{display:block}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid transparent;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:hsla(0,0%,100%,.05);--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:hsla(0,0%,100%,.1);--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:hsla(0,0%,100%,.07);--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}:root{--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-link-color:#c200c2;--docusaurus-announcement-bar-height:auto!important;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:transparent;--docusaurus-collapse-button-bg-hover:rgba(0,0,0,.1);--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}.navbar--dark{--ifm-navbar-background-color:#000;--ifm-menu-color:#fff;--ifm-menu-color-background-hover:hsla(0,0%,100%,.1)}.navbar--fixed-top{color:#fff;font-weight:700}.navbar--fixed-top a{color:#fff}details{background:#e2e2e2;margin-bottom:20px}details[open]{border-bottom:2px solid #c200c2}details iframe{padding:0 20px}details a{color:#666;font-size:.8em;text-align:right}.egghead-summary{background:#c200c2;border-radius:2px;color:#fff;cursor:pointer;margin:0;padding:5px}.egghead-link{font-style:italic;margin:5px;padding:5px}iframe{border:none}.dropdown__link{color:#000!important}div[class^=announcementBarContent]{font-size:20px;font-weight:700;line-height:40px;padding:8px 30px}div[class^=announcementBarContent] a{color:var(--ifm-color-primary-lightest)!important;display:inline-block;text-decoration:underline}div[class^=announcementBarContent] a:hover{color:var(--brand)!important}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;-moz-user-select:none;user-select:none}.hash-link:before{content:"#"}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{-moz-column-gap:.2rem;column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:transparent transparent transparent var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:hsla(0,0%,100%,.05);--docusaurus-collapse-button-bg-hover:hsla(0,0%,100%,.1)}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_b6E3,.sidebarLogo_isFc{display:none}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media only screen and (max-width:768px){.announcement{font-size:18px}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media only screen and (max-width:500px){.announcement{font-size:15px;line-height:22px;padding:6px 30px}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png b/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png new file mode 100644 index 00000000..c83185f8 Binary files /dev/null and b/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png differ diff --git a/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png b/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png new file mode 100644 index 00000000..1fd5c8be Binary files /dev/null and b/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png differ diff --git a/assets/js/042e7587.e0563d17.js b/assets/js/042e7587.e0563d17.js new file mode 100644 index 00000000..641ce1f0 --- /dev/null +++ b/assets/js/042e7587.e0563d17.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[518],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),c=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},m=function(e){var t=c(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),u=c(r),g=a,f=u["".concat(p,".").concat(g)]||u[g]||s[g]||o;return r?n.createElement(f,i(i({ref:t},m),{},{components:r})):n.createElement(f,i({ref:t},m))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var c=2;c{r.r(t),r.d(t,{assets:()=>m,contentTitle:()=>p,default:()=>g,frontMatter:()=>l,metadata:()=>c,toc:()=>u});var n=r(3117),a=r(102),o=(r(7294),r(3905)),i=["components"],l={id:"other-lang",title:"Porting to other languages"},p=void 0,c={unversionedId:"other-lang",id:"other-lang",title:"Porting to other languages",description:"Immer has been ported to other programming languages.",source:"@site/docs/other-lang.md",sourceDirName:".",slug:"/other-lang",permalink:"/immer/other-lang",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/other-lang.md",tags:[],version:"current",frontMatter:{id:"other-lang",title:"Porting to other languages"},sidebar:"Immer",previous:{title:"Supporting immer",permalink:"/immer/support"}},m={},u=[],s={toc:u};function g(e){var t=e.components,r=(0,a.Z)(e,i);return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Immer has been ported to other programming languages."),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Language"),(0,o.kt)("th",{parentName:"tr",align:null},"Link"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Java"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://babyfish-ct.github.io/jimmer-doc/"},"Jimmer"))))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0480b142.1f3b3884.js b/assets/js/0480b142.1f3b3884.js new file mode 100644 index 00000000..e8047341 --- /dev/null +++ b/assets/js/0480b142.1f3b3884.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[836],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var m=n.createContext({}),l=function(e){var t=n.useContext(m),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=l(e.components);return n.createElement(m.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,s=e.originalType,m=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=l(r),p=a,f=u["".concat(m,".").concat(p)]||u[p]||d[p]||s;return r?n.createElement(f,i(i({ref:t},c),{},{components:r})):n.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=r.length,i=new Array(s);i[0]=p;var o={};for(var m in t)hasOwnProperty.call(t,m)&&(o[m]=t[m]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>m,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var n=r(3117),a=r(102),s=(r(7294),r(3905)),i=["components"],o={id:"faq",title:"Frequently Asked Questions",sidebar_label:"FAQ"},m=void 0,l={unversionedId:"faq",id:"faq",title:"Frequently Asked Questions",description:"Q: How does Immer work?",source:"@site/docs/faq.md",sourceDirName:".",slug:"/faq",permalink:"/immer/faq",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/faq.md",tags:[],version:"current",frontMatter:{id:"faq",title:"Frequently Asked Questions",sidebar_label:"FAQ"},sidebar:"Immer",previous:{title:"External resources",permalink:"/immer/resources"},next:{title:"Pitfalls",permalink:"/immer/pitfalls"}},c={},u=[{value:"Q: How does Immer work?",id:"q-how-does-immer-work",level:2},{value:"Q: Does Immer use structural sharing? So that my selectors can be memoized and such?",id:"q-does-immer-use-structural-sharing-so-that-my-selectors-can-be-memoized-and-such",level:2},{value:"Q: Does Immer support deep updates?",id:"q-does-immer-support-deep-updates",level:2},{value:"Q: I can't rely on Proxies being present on my target environments. Can I use Immer?",id:"q-i-cant-rely-on-proxies-being-present-on-my-target-environments-can-i-use-immer",level:2},{value:"Q: Can I typecheck my data structures when using Immer?",id:"q-can-i-typecheck-my-data-structures-when-using-immer",level:2},{value:"Q: Can I store Date objects, functions etc in my state tree when using Immer?",id:"q-can-i-store-date-objects-functions-etc-in-my-state-tree-when-using-immer",level:2},{value:"Q: Can I use Maps and Sets?",id:"q-can-i-use-maps-and-sets",level:2},{value:"Q: Is it fast?",id:"q-is-it-fast",level:2},{value:"Q: Idea! Can Immer freeze the state for me?",id:"q-idea-can-immer-freeze-the-state-for-me",level:2}],d={toc:u};function p(e){var t=e.components,r=(0,a.Z)(e,i);return(0,s.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("center",null,(0,s.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,s.kt)("h2",{id:"q-how-does-immer-work"},"Q: How does Immer work?"),(0,s.kt)("p",null,"Read the (second part of the) ",(0,s.kt)("a",{parentName:"p",href:"https://medium.com/@mweststrate/introducing-immer-immutability-the-easy-way-9d73d8f71cb3"},"introduction blog"),"."),(0,s.kt)("h2",{id:"q-does-immer-use-structural-sharing-so-that-my-selectors-can-be-memoized-and-such"},"Q: Does Immer use structural sharing? So that my selectors can be memoized and such?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-does-immer-support-deep-updates"},"Q: Does Immer support deep updates?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-i-cant-rely-on-proxies-being-present-on-my-target-environments-can-i-use-immer"},"Q: I can't rely on Proxies being present on my target environments. Can I use Immer?"),(0,s.kt)("p",null,"A: Yes - ",(0,s.kt)("a",{parentName:"p",href:"/immer/installation#immer-on-older-javascript-environments"},"view details")),(0,s.kt)("h2",{id:"q-can-i-typecheck-my-data-structures-when-using-immer"},"Q: Can I typecheck my data structures when using Immer?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-can-i-store-date-objects-functions-etc-in-my-state-tree-when-using-immer"},"Q: Can I store ",(0,s.kt)("inlineCode",{parentName:"h2"},"Date")," objects, functions etc in my state tree when using Immer?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-can-i-use-maps-and-sets"},"Q: Can I use Maps and Sets?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-is-it-fast"},"Q: Is it fast?"),(0,s.kt)("p",null,"A: Yes"),(0,s.kt)("h2",{id:"q-idea-can-immer-freeze-the-state-for-me"},"Q: Idea! Can Immer freeze the state for me?"),(0,s.kt)("p",null,"A: Yes"))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0af7b35c.fb50d244.js b/assets/js/0af7b35c.fb50d244.js new file mode 100644 index 00000000..ff0b53a6 --- /dev/null +++ b/assets/js/0af7b35c.fb50d244.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[732],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),m=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=m(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,l=d(e,["components","mdxType","originalType","parentName"]),c=m(n),p=r,f=c["".concat(s,".").concat(p)]||c[p]||u[p]||o;return n?a.createElement(f,i(i({ref:t},l),{},{components:n})):a.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=p;var d={};for(var s in t)hasOwnProperty.call(t,s)&&(d[s]=t[s]);d.originalType=e,d[c]="string"==typeof e?e:r,i[1]=d;for(var m=2;m{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>p,frontMatter:()=>d,metadata:()=>m,toc:()=>c});var a=n(3117),r=n(102),o=(n(7294),n(3905)),i=["components"],d={id:"example-setstate",title:"React & Immer"},s=void 0,m={unversionedId:"example-setstate",id:"example-setstate",title:"React & Immer",description:" {\n const [todos, setTodos] = useState([\n {\n id: "React",\n title: "Learn React",\n done: true\n },\n {\n id: "Immer",\n title: "Try Immer",\n done: false\n }\n ]);\n\n const handleToggle = useCallback((id) => {\n setTodos(\n produce((draft) => {\n const todo = draft.find((todo) => todo.id === id);\n todo.done = !todo.done;\n })\n );\n }, []);\n\n const handleAdd = useCallback(() => {\n setTodos(\n produce((draft) => {\n draft.push({\n id: "todo_" + Math.random(),\n title: "A new todo",\n done: false\n });\n })\n );\n }, []);\n\n return (
{*/ See CodeSandbox */}
)\n}\n')),(0,o.kt)("h2",{id:"useimmer"},"useImmer"),(0,o.kt)("p",null,"Since all state updaters follow the same pattern where the update function is wrapped in ",(0,o.kt)("inlineCode",{parentName:"p"},"produce"),", it is also possible to simplify the above by leveraging the ",(0,o.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/use-immer"},"use-immer")," package that will wrap updater functions in ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," automatically:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import React, { useCallback } from "react";\nimport { useImmer } from "use-immer";\n\nconst TodoList = () => {\n const [todos, setTodos] = useImmer([\n {\n id: "React",\n title: "Learn React",\n done: true\n },\n {\n id: "Immer",\n title: "Try Immer",\n done: false\n }\n ]);\n\n const handleToggle = useCallback((id) => {\n setTodos((draft) => {\n const todo = draft.find((todo) => todo.id === id);\n todo.done = !todo.done;\n });\n }, []);\n\n const handleAdd = useCallback(() => {\n setTodos((draft) => {\n draft.push({\n id: "todo_" + Math.random(),\n title: "A new todo",\n done: false\n });\n });\n }, []);\n\n // etc\n')),(0,o.kt)("p",null,"For the full demo see ",(0,o.kt)("a",{parentName:"p",href:"https://codesandbox.io/s/use-immer-bvd5v?file=/src/index.js"},"CodeSandbox"),"."),(0,o.kt)("h2",{id:"usereducer--immer"},"useReducer + Immer"),(0,o.kt)("p",null,"Similarly to ",(0,o.kt)("inlineCode",{parentName:"p"},"useState"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"useReducer")," combines neatly with Immer as well, as demonstrated in this ",(0,o.kt)("a",{parentName:"p",href:"https://codesandbox.io/s/immer-usereducer-bqpzn?file=/src/index.js:0-1018"},"CodeSandbox"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import React, {useCallback, useReducer} from "react"\nimport {produce} from "immer"\n\nconst TodoList = () => {\n const [todos, dispatch] = useReducer(\n produce((draft, action) => {\n switch (action.type) {\n case "toggle":\n const todo = draft.find(todo => todo.id === action.id)\n todo.done = !todo.done\n break\n case "add":\n draft.push({\n id: action.id,\n title: "A new todo",\n done: false\n })\n break\n default:\n break\n }\n }),\n [\n /* initial todos */\n ]\n )\n\n const handleToggle = useCallback(id => {\n dispatch({\n type: "toggle",\n id\n })\n }, [])\n\n const handleAdd = useCallback(() => {\n dispatch({\n type: "add",\n id: "todo_" + Math.random()\n })\n }, [])\n\n // etc\n}\n')),(0,o.kt)("h2",{id:"useimmerreducer"},"useImmerReducer"),(0,o.kt)("p",null,"...which again, can be slightly shorted by ",(0,o.kt)("inlineCode",{parentName:"p"},"useImmerReducer")," from the ",(0,o.kt)("inlineCode",{parentName:"p"},"use-immer")," package (",(0,o.kt)("a",{parentName:"p",href:"https://codesandbox.io/s/useimmerreducer-sycpb?file=/src/index.js"},"demo"),"):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import React, { useCallback } from "react";\nimport { useImmerReducer } from "use-immer";\n\nconst TodoList = () => {\n const [todos, dispatch] = useImmerReducer(\n (draft, action) => {\n switch (action.type) {\n case "toggle":\n const todo = draft.find((todo) => todo.id === action.id);\n todo.done = !todo.done;\n break;\n case "add":\n draft.push({\n id: action.id,\n title: "A new todo",\n done: false\n });\n break;\n default:\n break;\n }\n },\n [ /* initial todos */ ]\n );\n\n //etc\n\n')),(0,o.kt)("h2",{id:"redux--immer"},"Redux + Immer"),(0,o.kt)("p",null,"Redux + Immer is extensively covered in the documentation of ",(0,o.kt)("a",{parentName:"p",href:"https://redux-toolkit.js.org/usage/immer-reducers"},"Redux Toolkit"),". For Redux without Redux Toolkit, the same trick as applied to ",(0,o.kt)("inlineCode",{parentName:"p"},"useReducer")," above can be applied: wrap the reducer function with ",(0,o.kt)("inlineCode",{parentName:"p"},"produce"),", and you can safely mutate the draft!"),(0,o.kt)("p",null,"For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\n// Reducer with initial state\nconst INITIAL_STATE = [\n /* bunch of todos */\n]\n\nconst todosReducer = produce((draft, action) => {\n switch (action.type) {\n case "toggle":\n const todo = draft.find(todo => todo.id === action.id)\n todo.done = !todo.done\n break\n case "add":\n draft.push({\n id: action.id,\n title: "A new todo",\n done: false\n })\n break\n default:\n break\n }\n})\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/17896441.9ee3f929.js b/assets/js/17896441.9ee3f929.js new file mode 100644 index 00000000..0bf6aa2b --- /dev/null +++ b/assets/js/17896441.9ee3f929.js @@ -0,0 +1 @@ +(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[918],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>v});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=s(n),p=r,v=d["".concat(c,".").concat(p)]||d[p]||m[p]||l;return n?a.createElement(v,o(o({ref:t},u),{},{components:n})):a.createElement(v,o({ref:t},u))}));function v(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=p;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[d]="string"==typeof e?e:r,o[1]=i;for(var s=2;s{"use strict";n.r(t),n.d(t,{default:()=>$t});var a=n(7294),r=n(1944),l=n(4700),o=a.createContext(null);function i(e){var t=e.children,n=function(e){return(0,a.useMemo)((function(){return{metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc}}),[e])}(e.content);return a.createElement(o.Provider,{value:n},t)}function c(){var e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocProvider");return e}function s(){var e,t=c(),n=t.metadata,l=t.frontMatter,o=t.assets;return a.createElement(r.d,{title:n.title,description:n.description,keywords:l.keywords,image:null!=(e=o.image)?e:l.image})}var u=n(6010),d=n(7524),m=n(3117),p=n(5999),v=n(9960);function f(e){var t=e.permalink,n=e.title,r=e.subLabel,l=e.isNext;return a.createElement(v.Z,{className:(0,u.Z)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},r&&a.createElement("div",{className:"pagination-nav__sublabel"},r),a.createElement("div",{className:"pagination-nav__label"},n))}function h(e){var t=e.previous,n=e.next;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,p.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&a.createElement(f,(0,m.Z)({},t,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(f,(0,m.Z)({},n,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function g(){var e=c().metadata;return a.createElement(h,{previous:e.previous,next:e.next})}var b=n(2263),E=n(143),y=n(5281),k=n(373),N=n(4477);var L={unreleased:function(e){var t=e.siteTitle,n=e.versionMetadata;return a.createElement(p.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){var t=e.siteTitle,n=e.versionMetadata;return a.createElement(p.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function C(e){var t=L[e.versionMetadata.banner];return a.createElement(t,e)}function Z(e){var t=e.versionLabel,n=e.to,r=e.onClick;return a.createElement(p.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(v.Z,{to:n,onClick:r},a.createElement(p.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){var t,n=e.className,r=e.versionMetadata,l=(0,b.Z)().siteConfig.title,o=(0,E.gA)({failfast:!0}).pluginId,i=(0,k.J)(o).savePreferredVersionName,c=(0,E.Jo)(o),s=c.latestDocSuggestion,d=c.latestVersionSuggestion,m=null!=s?s:(t=d).docs.find((function(e){return e.id===t.mainDocId}));return a.createElement("div",{className:(0,u.Z)(n,y.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(C,{siteTitle:l,versionMetadata:r})),a.createElement("div",{className:"margin-top--md"},a.createElement(Z,{versionLabel:d.label,to:m.path,onClick:function(){return i(d.name)}})))}function _(e){var t=e.className,n=(0,N.E)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function w(e){var t=e.className,n=(0,N.E)();return n.badge?a.createElement("span",{className:(0,u.Z)(t,y.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(p.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function x(e){var t=e.lastUpdatedAt,n=e.formattedLastUpdatedAt;return a.createElement(p.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function B(e){var t=e.lastUpdatedBy;return a.createElement(p.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function O(e){var t=e.lastUpdatedAt,n=e.formattedLastUpdatedAt,r=e.lastUpdatedBy;return a.createElement("span",{className:y.k.common.lastUpdated},a.createElement(p.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(x,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:r?a.createElement(B,{lastUpdatedBy:r}):""}},"Last updated{atDate}{byUser}"),!1)}var j=n(102);const A="iconEdit_Z9Sw";var H=["className"];function M(e){var t=e.className,n=(0,j.Z)(e,H);return a.createElement("svg",(0,m.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.Z)(A,t),"aria-hidden":"true"},n),a.createElement("g",null,a.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function S(e){var t=e.editUrl;return a.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:y.k.common.editThisPage},a.createElement(M,null),a.createElement(p.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const I="tag_zVej",P="tagRegular_sFm0",U="tagWithCount_h2kH";function z(e){var t=e.permalink,n=e.label,r=e.count;return a.createElement(v.Z,{href:t,className:(0,u.Z)(I,r?U:P)},n,r&&a.createElement("span",null,r))}const V="tags_jXut",D="tag_QGVx";function R(e){var t=e.tags;return a.createElement(a.Fragment,null,a.createElement("b",null,a.createElement(p.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),a.createElement("ul",{className:(0,u.Z)(V,"padding--none","margin-left--sm")},t.map((function(e){var t=e.label,n=e.permalink;return a.createElement("li",{key:n,className:D},a.createElement(z,{label:t,permalink:n}))}))))}const W="lastUpdated_vwxv";function F(e){return a.createElement("div",{className:(0,u.Z)(y.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(R,e)))}function q(e){var t=e.editUrl,n=e.lastUpdatedAt,r=e.lastUpdatedBy,l=e.formattedLastUpdatedAt;return a.createElement("div",{className:(0,u.Z)(y.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(S,{editUrl:t})),a.createElement("div",{className:(0,u.Z)("col",W)},(n||r)&&a.createElement(O,{lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:r})))}function G(){var e=c().metadata,t=e.editUrl,n=e.lastUpdatedAt,r=e.formattedLastUpdatedAt,l=e.lastUpdatedBy,o=e.tags,i=o.length>0,s=!!(t||n||l);return i||s?a.createElement("footer",{className:(0,u.Z)(y.k.docs.docFooter,"docusaurus-mt-lg")},i&&a.createElement(F,{tags:o}),s&&a.createElement(q,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:r})):null}var Y=n(6043),$=n(6668),J=["parentIndex"];function Q(e){var t=e.map((function(e){return Object.assign({},e,{parentIndex:-1,children:[]})})),n=Array(7).fill(-1);t.forEach((function(e,t){var a=n.slice(2,e.level);e.parentIndex=Math.max.apply(Math,a),n[e.level]=t}));var a=[];return t.forEach((function(e){var n=e.parentIndex,r=(0,j.Z)(e,J);n>=0?t[n].children.push(r):a.push(r)})),a}function X(e){var t=e.toc,n=e.minHeadingLevel,a=e.maxHeadingLevel;return t.flatMap((function(e){var t=X({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[Object.assign({},e,{children:t})]:t}))}function K(e){var t=e.getBoundingClientRect();return t.top===t.bottom?K(e.parentNode):t}function ee(e,t){var n,a,r=t.anchorTopOffset,l=e.find((function(e){return K(e).top>=r}));return l?function(e){return e.top>0&&e.bottom0})).map((function(e){return[e-1,[i]]}));return{lineClassNames:Object.fromEntries(c),code:n}}if(void 0===a)return{lineClassNames:{},code:n};for(var s=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return Ie(["js","jsBlock"],t);case"jsx":case"tsx":return Ie(["js","jsBlock","jsx"],t);case"html":return Ie(["js","jsBlock","html"],t);case"python":case"py":case"bash":return Ie(["bash"],t);case"markdown":case"md":return Ie(["html","jsx","bash"],t);default:return Ie(Object.keys(Se),t)}}(a,r),u=n.split("\n"),d=Object.fromEntries(r.map((function(e){return[e.className,{start:0,range:""}]}))),m=Object.fromEntries(r.filter((function(e){return e.line})).map((function(e){var t=e.className;return[e.line,t]}))),p=Object.fromEntries(r.filter((function(e){return e.block})).map((function(e){var t=e.className;return[e.block.start,t]}))),v=Object.fromEntries(r.filter((function(e){return e.block})).map((function(e){var t=e.className;return[e.block.end,t]}))),f=0;f0&&e[n-1]===t?e:e.concat(t)},Ke=function(e,t){var n=e.plain,a=Object.create(null),r=e.styles.reduce((function(e,n){var a=n.languages,r=n.style;return a&&!a.includes(t)||n.types.forEach((function(t){var n=$e({},e[t],r);e[t]=n})),e}),a);return r.root=n,r.plain=$e({},n,{backgroundColor:null}),r};function et(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&-1===t.indexOf(a)&&(n[a]=e[a]);return n}const tt=function(e){function t(){for(var t=this,n=[],a=arguments.length;a--;)n[a]=arguments[a];e.apply(this,n),Ye(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?Ke(e.theme,e.language):void 0;return t.themeDict=n})),Ye(this,"getLineProps",(function(e){var n=e.key,a=e.className,r=e.style,l=$e({},et(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),o=t.getThemeDict(t.props);return void 0!==o&&(l.style=o.plain),void 0!==r&&(l.style=void 0!==l.style?$e({},l.style,r):r),void 0!==n&&(l.key=n),a&&(l.className+=" "+a),l})),Ye(this,"getStyleForToken",(function(e){var n=e.types,a=e.empty,r=n.length,l=t.getThemeDict(t.props);if(void 0!==l){if(1===r&&"plain"===n[0])return a?{display:"inline-block"}:void 0;if(1===r&&!a)return l[n[0]];var o=a?{display:"inline-block"}:{},i=n.map((function(e){return l[e]}));return Object.assign.apply(Object,[o].concat(i))}})),Ye(this,"getTokenProps",(function(e){var n=e.key,a=e.className,r=e.style,l=e.token,o=$e({},et(e,["key","className","style","token"]),{className:"token "+l.types.join(" "),children:l.content,style:t.getStyleForToken(l),key:void 0});return void 0!==r&&(o.style=void 0!==o.style?$e({},o.style,r):r),void 0!==n&&(o.key=n),a&&(o.className+=" "+a),o})),Ye(this,"tokenize",(function(e,t,n,a){var r={code:t,grammar:n,language:a,tokens:[]};e.hooks.run("before-tokenize",r);var l=r.tokens=e.tokenize(r.code,r.grammar,r.language);return e.hooks.run("after-tokenize",r),l}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,a=e.code,r=e.children,l=this.getThemeDict(this.props),o=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],a=[0],r=[e.length],l=0,o=0,i=[],c=[i];o>-1;){for(;(l=a[o]++)0?u:["plain"],s=d):(u=Xe(u,d.type),d.alias&&(u=Xe(u,d.alias)),s=d.content),"string"==typeof s){var m=s.split(Je),p=m.length;i.push({types:u,content:m[0]});for(var v=1;v0&&(i=o.getRangeAt(0)),a.append(r),r.select(),r.selectionStart=0,r.selectionEnd=e.length;var c=!1;try{c=document.execCommand("copy")}catch(s){}r.remove(),i&&(o.removeAllRanges(),o.addRange(i)),l&&l.focus()}(t),o(!0),i.current=window.setTimeout((function(){o(!1)}),1e3)}),[t]);return(0,a.useEffect)((function(){return function(){return window.clearTimeout(i.current)}}),[]),a.createElement("button",{type:"button","aria-label":l?(0,p.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,p.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,p.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,u.Z)("clean-btn",n,ot.copyButton,l&&ot.copyButtonCopied),onClick:c},a.createElement("span",{className:ot.copyButtonIcons,"aria-hidden":"true"},a.createElement("svg",{className:ot.copyButtonIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),a.createElement("svg",{className:ot.copyButtonSuccessIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const ct="wordWrapButtonIcon_Bwma",st="wordWrapButtonEnabled_EoeP";function ut(e){var t=e.className,n=e.onClick,r=e.isEnabled,l=(0,p.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return a.createElement("button",{type:"button",onClick:n,className:(0,u.Z)("clean-btn",t,r&&st),"aria-label":l,title:l},a.createElement("svg",{className:ct,viewBox:"0 0 24 24","aria-hidden":"true"},a.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function dt(e){var t,n,r,l,o,i,c,s,d,p,v,f=e.children,h=e.className,g=void 0===h?"":h,b=e.metastring,E=e.title,y=e.showLineNumbers,k=e.language,N=(0,$.L)().prism,L=N.defaultLanguage,C=N.magicComments,Z=null!=(t=null!=k?k:null==(n=g.split(" ").find((function(e){return e.startsWith("language-")})))?void 0:n.replace(/language-/,""))?t:L,T=Be(),_=(r=(0,a.useState)(!1),l=r[0],o=r[1],i=(0,a.useState)(!1),c=i[0],s=i[1],d=(0,a.useRef)(null),p=(0,a.useCallback)((function(){var e=d.current.querySelector("code");l?e.removeAttribute("style"):(e.style.whiteSpace="pre-wrap",e.style.overflowWrap="anywhere"),o((function(e){return!e}))}),[d,l]),v=(0,a.useCallback)((function(){var e=d.current,t=e.scrollWidth>e.clientWidth||d.current.querySelector("code").hasAttribute("style");s(t)}),[d]),Fe(d,v),(0,a.useEffect)((function(){v()}),[l,v]),(0,a.useEffect)((function(){return window.addEventListener("resize",v,{passive:!0}),function(){window.removeEventListener("resize",v)}}),[v]),{codeBlockRef:d,isEnabled:l,isCodeScrollable:c,toggle:p}),w=function(e){var t,n;return null!=(t=null==e||null==(n=e.match(He))?void 0:n.groups.title)?t:""}(b)||E,x=Pe(f,{metastring:b,language:Z,magicComments:C}),B=x.lineClassNames,O=x.code,j=null!=y?y:function(e){return Boolean(null==e?void 0:e.includes("showLineNumbers"))}(b);return a.createElement(Ve,{as:"div",className:(0,u.Z)(g,Z&&!g.includes("language-"+Z)&&"language-"+Z)},w&&a.createElement("div",{className:De.codeBlockTitle},w),a.createElement("div",{className:De.codeBlockContent},a.createElement(tt,(0,m.Z)({},Ge,{theme:T,code:O,language:null!=Z?Z:"text"}),(function(e){var t=e.className,n=e.tokens,r=e.getLineProps,l=e.getTokenProps;return a.createElement("pre",{tabIndex:0,ref:_.codeBlockRef,className:(0,u.Z)(t,De.codeBlock,"thin-scrollbar")},a.createElement("code",{className:(0,u.Z)(De.codeBlockLines,j&&De.codeBlockLinesWithNumbering)},n.map((function(e,t){return a.createElement(lt,{key:t,line:e,getLineProps:r,getTokenProps:l,classNames:B[t],showLineNumbers:j})}))))})),a.createElement("div",{className:De.buttonGroup},(_.isEnabled||_.isCodeScrollable)&&a.createElement(ut,{className:De.codeButton,onClick:function(){return _.toggle()},isEnabled:_.isEnabled}),a.createElement(it,{className:De.codeButton,code:O}))))}var mt=["children"];function pt(e){var t=e.children,n=(0,j.Z)(e,mt),r=(0,we.Z)(),l=function(e){return a.Children.toArray(e).some((function(e){return(0,a.isValidElement)(e)}))?e:Array.isArray(e)?e.join(""):e}(t),o="string"==typeof l?dt:Re;return a.createElement(o,(0,m.Z)({key:String(r)},n),l)}const vt="details_lb9f",ft="isBrowser_bmU9",ht="collapsibleContent_i85q";var gt=["summary","children"];function bt(e){return!!e&&("SUMMARY"===e.tagName||bt(e.parentElement))}function Et(e,t){return!!e&&(e===t||Et(e.parentElement,t))}function yt(e){var t=e.summary,n=e.children,r=(0,j.Z)(e,gt),l=(0,we.Z)(),o=(0,a.useRef)(null),i=(0,Y.u)({initialState:!r.open}),c=i.collapsed,s=i.setCollapsed,d=(0,a.useState)(r.open),p=d[0],v=d[1],f=a.isValidElement(t)?t:a.createElement("summary",null,null!=t?t:"Details");return a.createElement("details",(0,m.Z)({},r,{ref:o,open:p,"data-collapsed":c,className:(0,u.Z)(vt,l&&ft,r.className),onMouseDown:function(e){bt(e.target)&&e.detail>1&&e.preventDefault()},onClick:function(e){e.stopPropagation();var t=e.target;bt(t)&&Et(t,o.current)&&(e.preventDefault(),c?(s(!1),v(!0)):s(!0))}}),f,a.createElement(Y.z,{lazy:!1,collapsed:c,disableSSRStyle:!0,onCollapseTransitionEnd:function(e){s(e),v(!e)}},a.createElement("div",{className:ht},n)))}const kt="details_b_Ee";function Nt(e){var t=Object.assign({},(function(e){if(null==e)throw new TypeError("Cannot destructure "+e)}(e),e));return a.createElement(yt,(0,m.Z)({},t,{className:(0,u.Z)("alert alert--info",kt,t.className)}))}function Lt(e){return a.createElement(Ce,e)}const Ct="containsTaskList_mC6p";const Zt="img_ev3q";const Tt="admonition_LlT9",_t="admonitionHeading_tbUL",wt="admonitionIcon_kALy",xt="admonitionContent_S0QG";var Bt={note:{infimaClassName:"secondary",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:a.createElement(p.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:a.createElement(p.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 16 16"},a.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:a.createElement(p.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},Ot={secondary:"note",important:"info",success:"tip",warning:"danger"};function jt(e){var t,n=function(e){var t=a.Children.toArray(e),n=t.find((function(e){var t;return a.isValidElement(e)&&"mdxAdmonitionTitle"===(null==(t=e.props)?void 0:t.mdxType)})),r=a.createElement(a.Fragment,null,t.filter((function(e){return e!==n})));return{mdxAdmonitionTitle:n,rest:r}}(e.children),r=n.mdxAdmonitionTitle,l=n.rest;return Object.assign({},e,{title:null!=(t=e.title)?t:r,children:l})}const At={head:function(e){var t=a.Children.map(e.children,(function(e){return a.isValidElement(e)?function(e){var t;if(null!=(t=e.props)&&t.mdxType&&e.props.originalType){var n=e.props,r=(n.mdxType,n.originalType,(0,j.Z)(n,_e));return a.createElement(e.props.originalType,r)}return e}(e):e}));return a.createElement(Te.Z,e,t)},code:function(e){var t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return a.Children.toArray(e.children).every((function(e){var n;return"string"==typeof e&&!e.includes("\n")||(0,a.isValidElement)(e)&&t.includes(null==(n=e.props)?void 0:n.mdxType)}))?a.createElement("code",e):a.createElement(pt,e)},a:function(e){return a.createElement(v.Z,e)},pre:function(e){var t;return a.createElement(pt,(0,a.isValidElement)(e.children)&&"code"===(null==(t=e.children.props)?void 0:t.originalType)?e.children.props:Object.assign({},e))},details:function(e){var t=a.Children.toArray(e.children),n=t.find((function(e){var t;return a.isValidElement(e)&&"summary"===(null==(t=e.props)?void 0:t.mdxType)})),r=a.createElement(a.Fragment,null,t.filter((function(e){return e!==n})));return a.createElement(Nt,(0,m.Z)({},e,{summary:n}),r)},ul:function(e){return a.createElement("ul",(0,m.Z)({},e,{className:(t=e.className,(0,u.Z)(t,(null==t?void 0:t.includes("contains-task-list"))&&Ct))}));var t},img:function(e){return a.createElement("img",(0,m.Z)({loading:"lazy"},e,{className:(t=e.className,(0,u.Z)(t,Zt))}));var t},h1:function(e){return a.createElement(Lt,(0,m.Z)({as:"h1"},e))},h2:function(e){return a.createElement(Lt,(0,m.Z)({as:"h2"},e))},h3:function(e){return a.createElement(Lt,(0,m.Z)({as:"h3"},e))},h4:function(e){return a.createElement(Lt,(0,m.Z)({as:"h4"},e))},h5:function(e){return a.createElement(Lt,(0,m.Z)({as:"h5"},e))},h6:function(e){return a.createElement(Lt,(0,m.Z)({as:"h6"},e))},admonition:function(e){var t=jt(e),n=t.children,r=t.type,l=t.title,o=t.icon,i=function(e){var t,n=null!=(t=Ot[e])?t:e,a=Bt[n];return a||(console.warn('No admonition config found for admonition type "'+n+'". Using Info as fallback.'),Bt.info)}(r),c=null!=l?l:i.label,s=i.iconComponent,d=null!=o?o:a.createElement(s,null);return a.createElement("div",{className:(0,u.Z)(y.k.common.admonition,y.k.common.admonitionType(e.type),"alert","alert--"+i.infimaClassName,Tt)},a.createElement("div",{className:_t},a.createElement("span",{className:wt},d),c),a.createElement("div",{className:xt},n))},mermaid:n(1875).Z};function Ht(e){var t=e.children;return a.createElement(Ze.Zo,{components:At},t)}function Mt(e){var t,n,r,l,o=e.children,i=(t=c(),n=t.metadata,r=t.frontMatter,l=t.contentTitle,r.hide_title||void 0!==l?null:n.title);return a.createElement("div",{className:(0,u.Z)(y.k.docs.docMarkdown,"markdown")},i&&a.createElement("header",null,a.createElement(Ce,{as:"h1"},i)),a.createElement(Ht,null,o))}var St=n(3651),It=n(8596),Pt=n(4996);function Ut(e){return a.createElement("svg",(0,m.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const zt="breadcrumbHomeIcon_YNFT";function Vt(){var e=(0,Pt.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(v.Z,{"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(Ut,{className:zt})))}const Dt="breadcrumbsContainer_Z_bl";function Rt(e){var t=e.children,n=e.href,r="breadcrumbs__link";return e.isLast?a.createElement("span",{className:r,itemProp:"name"},t):n?a.createElement(v.Z,{className:r,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:r},t)}function Wt(e){var t=e.children,n=e.active,r=e.index,l=e.addMicrodata;return a.createElement("li",(0,m.Z)({},l&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,u.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(r+1)}))}function Ft(){var e=(0,St.s1)(),t=(0,It.Ns)();return e?a.createElement("nav",{className:(0,u.Z)(y.k.docs.docBreadcrumbs,Dt),"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(Vt,null),e.map((function(t,n){var r=n===e.length-1;return a.createElement(Wt,{key:n,active:r,index:n,addMicrodata:!!t.href},a.createElement(Rt,{href:t.href,isLast:r},t.label))})))):null}const qt="docItemContainer_Djhp",Gt="docItemCol_VOVn";function Yt(e){var t,n,r,l,o,i,s=e.children,m=(t=c(),n=t.frontMatter,r=t.toc,l=(0,d.i)(),o=n.hide_table_of_contents,i=!o&&r.length>0,{hidden:o,mobile:i?a.createElement(he,null):void 0,desktop:!i||"desktop"!==l&&"ssr"!==l?void 0:a.createElement(ye,null)});return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,u.Z)("col",!m.hidden&&Gt)},a.createElement(_,null),a.createElement("div",{className:qt},a.createElement("article",null,a.createElement(Ft,null),a.createElement(w,null),m.mobile,a.createElement(Mt,null,s),a.createElement(G,null)),a.createElement(g,null))),m.desktop&&a.createElement("div",{className:"col col--3"},m.desktop))}function $t(e){var t="docs-doc-id-"+e.content.metadata.unversionedId,n=e.content;return a.createElement(i,{content:e.content},a.createElement(r.FG,{className:t},a.createElement(s,null),a.createElement(Yt,null,a.createElement(n,null))))}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>i,q:()=>o});var a=n(7294),r=n(4700),l=a.createContext(null);function o(e){var t=e.children,n=e.version;return a.createElement(l.Provider,{value:n},t)}function i(){var e=(0,a.useContext)(l);if(null===e)throw new r.i6("DocsVersionProvider");return e}},7594:(e,t)=>{function n(e){let t,n=[];for(let a of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(a))n.push(parseInt(a,10));else if(t=a.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,a,r,l]=t;if(a&&l){a=parseInt(a),l=parseInt(l);const e=a{n.r(t),n.d(t,{default:()=>xe});var a=n(7294),r=n(6010),l=n(1944),i=n(5281),o=n(3320),c=n(3651),s=n(4477),d=n(1116),m=n(7961),u=n(5999),b=n(2466),p=n(5936);const v="backToTopButton_sjWU",h="backToTopButtonShow_xfvO";function E(){var e=function(e){var t=e.threshold,n=(0,a.useState)(!1),r=n[0],l=n[1],i=(0,a.useRef)(!1),o=(0,b.Ct)(),c=o.startScroll,s=o.cancelScroll;return(0,b.RF)((function(e,n){var a=e.scrollY,r=null==n?void 0:n.scrollY;r&&(i.current?i.current=!1:a>=r?(s(),l(!1)):a{n.r(t),n.d(t,{default:()=>o});var a=n(7294),r=n(5999),l=n(1944),i=n(7961);function o(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,r.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(i.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(r.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(r.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(r.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>o,q:()=>i});var a=n(7294),r=n(4700),l=a.createContext(null);function i(e){var t=e.children,n=e.version;return a.createElement(l.Provider,{value:n},t)}function o(){var e=(0,a.useContext)(l);if(null===e)throw new r.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/2b810e00.dd4c0b92.js b/assets/js/2b810e00.dd4c0b92.js new file mode 100644 index 00000000..732b7de9 --- /dev/null +++ b/assets/js/2b810e00.dd4c0b92.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[222],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function d(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):d(d({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},l="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),l=p(n),m=a,f=l["".concat(s,".").concat(m)]||l[m]||c[m]||o;return n?r.createElement(f,d(d({ref:t},u),{},{components:n})):r.createElement(f,d({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,d=new Array(o);d[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[l]="string"==typeof e?e:a,d[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>m,frontMatter:()=>i,metadata:()=>p,toc:()=>l});var r=n(3117),a=n(102),o=(n(7294),n(3905)),d=["components"],i={id:"update-patterns",title:"Update patterns"},s=void 0,p={unversionedId:"update-patterns",id:"update-patterns",title:"Update patterns",description:"Working with immutable data, before Immer, used to mean learning all the immutable update patterns.",source:"@site/docs/update-patterns.md",sourceDirName:".",slug:"/update-patterns",permalink:"/immer/update-patterns",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/update-patterns.md",tags:[],version:"current",frontMatter:{id:"update-patterns",title:"Update patterns"},sidebar:"Immer",previous:{title:"React & Immer",permalink:"/immer/example-setstate"},next:{title:"API overview",permalink:"/immer/api"}},u={},l=[{value:"Object mutations",id:"object-mutations",level:3},{value:"Array mutations",id:"array-mutations",level:3},{value:"Nested data structures",id:"nested-data-structures",level:3}],c={toc:l};function m(e){var t=e.components,n=(0,a.Z)(e,d);return(0,o.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("center",null,(0,o.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,o.kt)("p",null,"Working with immutable data, before Immer, used to mean learning all the immutable update patterns."),(0,o.kt)("p",null,"To help 'unlearning' those patterns here is an overview how you can leverage the built-in JavaScript APIs to update objects and collections:"),(0,o.kt)("h3",{id:"object-mutations"},"Object mutations"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst todosObj = {\n id1: {done: false, body: "Take out the trash"},\n id2: {done: false, body: "Check Email"}\n}\n\n// add\nconst addedTodosObj = produce(todosObj, draft => {\n draft["id3"] = {done: false, body: "Buy bananas"}\n})\n\n// delete\nconst deletedTodosObj = produce(todosObj, draft => {\n delete draft["id1"]\n})\n\n// update\nconst updatedTodosObj = produce(todosObj, draft => {\n draft["id1"].done = true\n})\n')),(0,o.kt)("h3",{id:"array-mutations"},"Array mutations"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst todosArray = [\n {id: "id1", done: false, body: "Take out the trash"},\n {id: "id2", done: false, body: "Check Email"}\n]\n\n// add\nconst addedTodosArray = produce(todosArray, draft => {\n draft.push({id: "id3", done: false, body: "Buy bananas"})\n})\n\n// delete by index\nconst deletedTodosArray = produce(todosArray, draft => {\n draft.splice(3 /*the index */, 1)\n})\n\n// update by index\nconst updatedTodosArray = produce(todosArray, draft => {\n draft[3].done = true\n})\n\n// insert at index\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.splice(3, 0, {id: "id3", done: false, body: "Buy bananas"})\n})\n\n// remove last item\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.pop()\n})\n\n// remove first item\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.shift()\n})\n\n// add item at the beginning of the array\nconst addedTodosArray = produce(todosArray, draft => {\n draft.unshift({id: "id3", done: false, body: "Buy bananas"})\n})\n\n// delete by id\nconst deletedTodosArray = produce(todosArray, draft => {\n const index = draft.findIndex(todo => todo.id === "id1")\n if (index !== -1) draft.splice(index, 1)\n})\n\n// update by id\nconst updatedTodosArray = produce(todosArray, draft => {\n const index = draft.findIndex(todo => todo.id === "id1")\n if (index !== -1) draft[index].done = true\n})\n\n// filtering items\nconst updatedTodosArray = produce(todosArray, draft => {\n // creating a new state is simpler in this example\n // (note that we don\'t need produce in this case,\n // but as shown below, if the filter is not on the top\n // level produce is still pretty useful)\n return draft.filter(todo => todo.done)\n})\n')),(0,o.kt)("h3",{id:"nested-data-structures"},"Nested data structures"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\n// example complex data structure\nconst store = {\n users: new Map([\n [\n "17",\n {\n name: "Michel",\n todos: [\n {\n title: "Get coffee",\n done: false\n }\n ]\n }\n ]\n ])\n}\n\n// updating something deeply in-an-object-in-an-array-in-a-map-in-an-object:\nconst nextStore = produce(store, draft => {\n draft.users.get("17").todos[0].done = true\n})\n\n// filtering out all unfinished todo\'s\nconst nextStore = produce(store, draft => {\n const user = draft.users.get("17")\n // when filtering, creating a fresh collection is simpler than\n // removing irrelevant items\n user.todos = user.todos.filter(todo => todo.done)\n})\n')),(0,o.kt)("p",null,"Note that many array operations can be used to insert multiple items at once by passing multiple arguments or using the spread operation: ",(0,o.kt)("inlineCode",{parentName:"p"},"todos.unshift(...items)"),"."),(0,o.kt)("p",null,"Note that when working with arrays that contain objects that are typically identified by some id, we recommend to use ",(0,o.kt)("inlineCode",{parentName:"p"},"Map")," or index based objects (as shown above) instead of performing frequent find operations, lookup tables perform much better in general."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5fbc5cf1.01b5063b.js b/assets/js/5fbc5cf1.01b5063b.js new file mode 100644 index 00000000..75120e58 --- /dev/null +++ b/assets/js/5fbc5cf1.01b5063b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[207],{3905:(t,e,a)=>{a.d(e,{Zo:()=>d,kt:()=>k});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var o=n.createContext({}),m=function(t){var e=n.useContext(o),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},d=function(t){var e=m(t.components);return n.createElement(o.Provider,{value:e},t.children)},s="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},c=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,o=t.parentName,d=p(t,["components","mdxType","originalType","parentName"]),s=m(a),c=r,k=s["".concat(o,".").concat(c)]||s[c]||u[c]||l;return a?n.createElement(k,i(i({ref:e},d),{},{components:a})):n.createElement(k,i({ref:e},d))}));function k(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=c;var p={};for(var o in e)hasOwnProperty.call(e,o)&&(p[o]=e[o]);p.originalType=t,p[s]="string"==typeof t?t:r,i[1]=p;for(var m=2;m{a.r(e),a.d(e,{assets:()=>d,contentTitle:()=>o,default:()=>c,frontMatter:()=>p,metadata:()=>m,toc:()=>s});var n=a(3117),r=a(102),l=(a(7294),a(3905)),i=["components"],p={id:"api",title:"API overview"},o=void 0,m={unversionedId:"api",id:"api",title:"API overview",description:"| Exported name | Description | Section |",source:"@site/docs/api.md",sourceDirName:".",slug:"/api",permalink:"/immer/api",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/api.md",tags:[],version:"current",frontMatter:{id:"api",title:"API overview"},sidebar:"Immer",previous:{title:"Update patterns",permalink:"/immer/update-patterns"},next:{title:"Map and Set",permalink:"/immer/map-set"}},d={},s=[{value:"Importing immer",id:"importing-immer",level:2}],u={toc:s};function c(t){var e=t.components,a=(0,r.Z)(t,i);return(0,l.kt)("wrapper",(0,n.Z)({},u,a,{components:e,mdxType:"MDXLayout"}),(0,l.kt)("center",null,(0,l.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Exported name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Section"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"produce")),(0,l.kt)("td",{parentName:"tr",align:null},"The core API of Immer: ",(0,l.kt)("inlineCode",{parentName:"td"},'import {produce} from "immer"')),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/produce"},"Produce"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"applyPatches")),(0,l.kt)("td",{parentName:"tr",align:null},"Given a base state or draft, and a set of patches, applies the patches"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/patches"},"Patches"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"castDraft")),(0,l.kt)("td",{parentName:"tr",align:null},"Converts any immutable type to its mutable counterpart. This is just a cast and doesn't actually do anything."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/typescript"},"TypeScript"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"castImmutable")),(0,l.kt)("td",{parentName:"tr",align:null},"Converts any mutable type to its immutable counterpart. This is just a cast and doesn't actually do anything."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/typescript"},"TypeScript"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"createDraft")),(0,l.kt)("td",{parentName:"tr",align:null},"Given a base state, creates a mutable draft for which any modifications will be recorded"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/async"},"Async"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"current")),(0,l.kt)("td",{parentName:"tr",align:null},"Given a draft object (doesn't have to be a tree root), takes a snapshot of the current state of the draft"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/current"},"Current"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Draft")),(0,l.kt)("td",{parentName:"tr",align:null},"Exposed TypeScript type to convert an immutable type to a mutable type"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/typescript"},"TypeScript"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"enableMapSet()")),(0,l.kt)("td",{parentName:"tr",align:null},"Enables support for ",(0,l.kt)("inlineCode",{parentName:"td"},"Map")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"Set")," collections."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/installation#pick-your-immer-version"},"Installation"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"enablePatches()")),(0,l.kt)("td",{parentName:"tr",align:null},"Enables support for JSON patches."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"./installation#pick-your-immer-version"},"Installation"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"finishDraft")),(0,l.kt)("td",{parentName:"tr",align:null},"Given an draft created using ",(0,l.kt)("inlineCode",{parentName:"td"},"createDraft"),", seals the draft and produces and returns the next immutable state that captures all the changes"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/async"},"Async"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"freeze(obj, deep?)")),(0,l.kt)("td",{parentName:"tr",align:null},"Freezes draftable objects. Returns the original object. By default freezes shallowly, but if the second argument is ",(0,l.kt)("inlineCode",{parentName:"td"},"true")," it will freeze recursively."),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Immer")),(0,l.kt)("td",{parentName:"tr",align:null},'constructor that can be used to create a second "immer" instance (exposing all APIs listed in this instance), that doesn\'t share its settings with global instance.'),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"immerable")),(0,l.kt)("td",{parentName:"tr",align:null},"Symbol that can be added to a constructor or prototype, to indicate that Immer should treat the class as something that can be safely drafted"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/complex-objects"},"Classes"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Immutable")),(0,l.kt)("td",{parentName:"tr",align:null},"Exposed TypeScript type to convert mutable types to immutable types"),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"isDraft")),(0,l.kt)("td",{parentName:"tr",align:null},"Returns true if the given object is a draft object"),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"isDraftable")),(0,l.kt)("td",{parentName:"tr",align:null},"Returns true if Immer is capable of turning this object into a draft. Which is true for: arrays, objects without prototype, objects with ",(0,l.kt)("inlineCode",{parentName:"td"},"Object")," as their prototype, objects that have the ",(0,l.kt)("inlineCode",{parentName:"td"},"immerable")," symbol on their constructor or prototype"),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"nothing")),(0,l.kt)("td",{parentName:"tr",align:null},"Value that can be returned from a recipe, to indicate that the value ",(0,l.kt)("inlineCode",{parentName:"td"},"undefined")," should be produced"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/return"},"Return"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"original")),(0,l.kt)("td",{parentName:"tr",align:null},"Given a draft object (doesn't have to be a tree root), returns the original object at the same path in the original state tree, if present"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/original"},"Original"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Patch")),(0,l.kt)("td",{parentName:"tr",align:null},"Exposed TypeScript type, describes the shape of an (inverse) patch object"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/patches"},"Patches"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"produceWithPatches")),(0,l.kt)("td",{parentName:"tr",align:null},"Works the same as ",(0,l.kt)("inlineCode",{parentName:"td"},"produce"),", but instead of just returning the produced object, it returns a tuple, consisting of ",(0,l.kt)("inlineCode",{parentName:"td"},"[result, patches, inversePatches]"),"."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/patches"},"Patches"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"setAutoFreeze")),(0,l.kt)("td",{parentName:"tr",align:null},"Enables / disables automatic freezing of the trees produces. By default enabled."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/freezing"},"Freezing"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"setUseStrictShallowCopy")),(0,l.kt)("td",{parentName:"tr",align:null},"Can be used to enable strict shallow copy. If enable, immer copies non-enumerable properties as much as possible."),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/immer/complex-objects"},"Classes"))))),(0,l.kt)("h2",{id:"importing-immer"},"Importing immer"),(0,l.kt)("p",null,"In most cases, the only thing you need to import from Immer is ",(0,l.kt)("inlineCode",{parentName:"p"},"produce"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n')),(0,l.kt)("p",null,"Note that in older versions, ",(0,l.kt)("inlineCode",{parentName:"p"},"produce")," was also available as default export (e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},'import produce from "immer"')," was also valid, but that is no longer the case to improve eco system compatibility."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/62d444b9.96d43566.js b/assets/js/62d444b9.96d43566.js new file mode 100644 index 00000000..8656f5f4 --- /dev/null +++ b/assets/js/62d444b9.96d43566.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[285],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>f});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},m=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),c=p(r),u=n,f=c["".concat(l,".").concat(u)]||c[u]||d[u]||o;return r?a.createElement(f,i(i({ref:t},m),{},{components:r})):a.createElement(f,i({ref:t},m))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:n,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>u,frontMatter:()=>s,metadata:()=>p,toc:()=>c});var a=r(3117),n=r(102),o=(r(7294),r(3905)),i=["components"],s={id:"performance",title:"Immer performance"},l=void 0,p={unversionedId:"performance",id:"performance",title:"Immer performance",description:" d.push(x))")," is exponentially slower than ",(0,o.kt)("inlineCode",{parentName:"p"},"produce(base, d => { for (let x of y) d.push(x)})")))}u.isMDXComponent=!0},9943:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png"}}]); \ No newline at end of file diff --git a/assets/js/74860b1a.14c24b29.js b/assets/js/74860b1a.14c24b29.js new file mode 100644 index 00000000..69993100 --- /dev/null +++ b/assets/js/74860b1a.14c24b29.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[133],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=d(r),m=a,f=u["".concat(l,".").concat(m)]||u[m]||c[m]||o;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var d=2;d{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>d,toc:()=>u});var n=r(3117),a=r(102),o=(r(7294),r(3905)),i=["components"],s={id:"pitfalls",title:"Pitfalls"},l=void 0,d={unversionedId:"pitfalls",id:"pitfalls",title:"Pitfalls",description:"Performance tips",source:"@site/docs/pitfalls.md",sourceDirName:".",slug:"/pitfalls",permalink:"/immer/pitfalls",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/pitfalls.md",tags:[],version:"current",frontMatter:{id:"pitfalls",title:"Pitfalls"},sidebar:"Immer",previous:{title:"FAQ",permalink:"/immer/faq"},next:{title:"Built with Immer",permalink:"/immer/built-with"}},p={},u=[{value:"Performance tips",id:"performance-tips",level:3},{value:"Don't reassign the recipe argument",id:"dont-reassign-the-recipe-argument",level:3},{value:"Immer only supports unidirectional trees",id:"immer-only-supports-unidirectional-trees",level:3},{value:"Never explicitly return undefined from a producer",id:"never-explicitly-return-undefined-from-a-producer",level:3},{value:"Don't mutate exotic objects",id:"dont-mutate-exotic-objects",level:3},{value:"Classes should be made draftable or not mutated",id:"classes-should-be-made-draftable-or-not-mutated",level:3},{value:"Only valid indices and length can be mutated on Arrays",id:"only-valid-indices-and-length-can-be-mutated-on-arrays",level:3},{value:"Data not originating from the state will never be drafted",id:"data-not-originating-from-the-state-will-never-be-drafted",level:3},{value:"Immer patches are not necessarily optimal",id:"immer-patches-are-not-necessarily-optimal",level:3},{value:"Always use the result of nested producers",id:"always-use-the-result-of-nested-producers",level:3},{value:"Drafts aren't referentially equal",id:"drafts-arent-referentially-equal",level:3}],c={toc:u};function m(e){var t=e.components,r=(0,a.Z)(e,i);return(0,o.kt)("wrapper",(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("center",null,(0,o.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,o.kt)("h3",{id:"performance-tips"},"Performance tips"),(0,o.kt)("p",null,"For performance tips, see ",(0,o.kt)("a",{parentName:"p",href:"/immer/performance#performance-tips"},"Performance Tips"),"."),(0,o.kt)("h3",{id:"dont-reassign-the-recipe-argument"},"Don't reassign the recipe argument"),(0,o.kt)("p",null,"Never reassign the ",(0,o.kt)("inlineCode",{parentName:"p"},"draft")," argument (example: ",(0,o.kt)("inlineCode",{parentName:"p"},"draft = myCoolNewState"),"). Instead, either modify the ",(0,o.kt)("inlineCode",{parentName:"p"},"draft")," or return a new state. See ",(0,o.kt)("a",{parentName:"p",href:"/immer/return"},"Returning data from producers"),"."),(0,o.kt)("h3",{id:"immer-only-supports-unidirectional-trees"},"Immer only supports unidirectional trees"),(0,o.kt)("p",null,"Immer assumes your state to be a unidirectional tree. That is, no object should appear twice in the tree, there should be no circular references. There should be exactly one path from the root to any node of the tree."),(0,o.kt)("h3",{id:"never-explicitly-return-undefined-from-a-producer"},"Never explicitly return ",(0,o.kt)("inlineCode",{parentName:"h3"},"undefined")," from a producer"),(0,o.kt)("p",null,"It is possible to return values from producers, except, it is not possible to return ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," that way, as it is indistinguishable from not updating the draft at all! If you want to replace the draft with ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined"),", just return ",(0,o.kt)("inlineCode",{parentName:"p"},"nothing")," from the producer."),(0,o.kt)("h3",{id:"dont-mutate-exotic-objects"},"Don't mutate exotic objects"),(0,o.kt)("p",null,"Immer ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/immerjs/immer/issues/504"},"does not support exotic objects")," such as window.location."),(0,o.kt)("h3",{id:"classes-should-be-made-draftable-or-not-mutated"},"Classes should be made draftable or not mutated"),(0,o.kt)("p",null,"You will need to enable your own classes to work properly with Immer. For docs on the topic, check out the section on ",(0,o.kt)("a",{parentName:"p",href:"/immer/complex-objects"},"working with complex objects"),"."),(0,o.kt)("h3",{id:"only-valid-indices-and-length-can-be-mutated-on-arrays"},"Only valid indices and length can be mutated on Arrays"),(0,o.kt)("p",null,"For arrays, only numeric properties and the ",(0,o.kt)("inlineCode",{parentName:"p"},"length")," property can be mutated. Custom properties are not preserved on arrays."),(0,o.kt)("h3",{id:"data-not-originating-from-the-state-will-never-be-drafted"},"Data not originating from the state will never be drafted"),(0,o.kt)("p",null,"Note that data that comes from the closure, and not from the base state, will never be drafted, even when the data has become part of the new draft."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},"function onReceiveTodo(todo) {\n const nextTodos = produce(todos, draft => {\n draft.todos[todo.id] = todo\n // Note, because 'todo' is coming from external, and not from the 'draft',\n // it isn't draft so the following modification affects the original todo!\n draft.todos[todo.id].done = true\n\n // The reason for this, is that it means that the behavior of the 2 lines above\n // is equivalent to code, making this whole process more consistent\n todo.done = true\n draft.todos[todo.id] = todo\n })\n}\n")),(0,o.kt)("h3",{id:"immer-patches-are-not-necessarily-optimal"},"Immer patches are not necessarily optimal"),(0,o.kt)("p",null,"The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible."),(0,o.kt)("h3",{id:"always-use-the-result-of-nested-producers"},"Always use the result of nested producers"),(0,o.kt)("p",null,"Nested ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," calls are supported, but note that ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," will ",(0,o.kt)("em",{parentName:"p"},"always")," produce a new state. So even when passing a draft to a nested produce, the changes made by the inner produce won't be visible in the draft of the outer produce; those changes will only be visible in the output that the inner ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," returns. In other words, when using nested produce, you get a draft of a draft and the result of the inner produce should be merged back into the original draft (or returned). For example ",(0,o.kt)("inlineCode",{parentName:"p"},'produce(state, draft => { produce(draft.user, userDraft => { userDraft.name += "!" })})')," won't work as the output of the inner produce isn't used. The correct way to use nested producers is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'produce(state, draft => {\n draft.user = produce(draft.user, userDraft => {\n userDraft.name += "!"\n })\n})\n')),(0,o.kt)("h3",{id:"drafts-arent-referentially-equal"},"Drafts aren't referentially equal"),(0,o.kt)("p",null,"Draft objects in Immer are wrapped in ",(0,o.kt)("inlineCode",{parentName:"p"},"Proxy"),", so you cannot use ",(0,o.kt)("inlineCode",{parentName:"p"},"==")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"===")," to test equality between an original object and its equivalent draft (eg. when matching a specific element in an array). Instead, you can use the ",(0,o.kt)("inlineCode",{parentName:"p"},"original")," helper:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},"const remove = produce((list, element) => {\n const index = list.indexOf(element) // this won't work!\n const index = original(list).indexOf(element) // do this instead\n if (index > -1) list.splice(index, 1)\n})\n\nconst values = [a, b, c]\nremove(values, a)\n")),(0,o.kt)("p",null,"If possible, it's recommended to perform the comparison outside the ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," function, or to use a unique identifier property like ",(0,o.kt)("inlineCode",{parentName:"p"},".id")," instead, to avoid needing to use ",(0,o.kt)("inlineCode",{parentName:"p"},"original"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/78f86360.36d82662.js b/assets/js/78f86360.36d82662.js new file mode 100644 index 00000000..0fc1e0ba --- /dev/null +++ b/assets/js/78f86360.36d82662.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[973],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>h});var a=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function m(e){for(var t=1;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):m(m({},t),e)),r},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},s="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,i=e.mdxType,n=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),s=p(r),d=i,h=s["".concat(l,".").concat(d)]||s[d]||c[d]||n;return r?a.createElement(h,m(m({ref:t},u),{},{components:r})):a.createElement(h,m({ref:t},u))}));function h(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=r.length,m=new Array(n);m[0]=d;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[s]="string"==typeof e?e:i,m[1]=o;for(var p=2;p{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>p,toc:()=>s});var a=r(3117),i=r(102),n=(r(7294),r(3905)),m=["components"],o={id:"built-with",title:"Built with Immer"},l=void 0,p={unversionedId:"built-with",id:"built-with",title:"Built with Immer",description:"- react-copy-write Immutable state with a mutable API",source:"@site/docs/built-with.md",sourceDirName:".",slug:"/built-with",permalink:"/immer/built-with",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/built-with.md",tags:[],version:"current",frontMatter:{id:"built-with",title:"Built with Immer"},sidebar:"Immer",previous:{title:"Pitfalls",permalink:"/immer/pitfalls"},next:{title:"Supporting immer",permalink:"/immer/support"}},u={},s=[],c={toc:s};function d(e){var t=e.components,r=(0,i.Z)(e,m);return(0,n.kt)("wrapper",(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("center",null,(0,n.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/aweary/react-copy-write"},"react-copy-write")," ",(0,n.kt)("em",{parentName:"li"},"Immutable state with a mutable API")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/reduxjs/redux-toolkit"},"redux-toolkit")," ",(0,n.kt)("em",{parentName:"li"},"The official, opinionated, batteries-included toolset for efficient Redux development")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://gist.github.com/kitze/fb65f527803a93fb2803ce79a792fff8"},"immer based handleActions")," ",(0,n.kt)("em",{parentName:"li"},"Boilerplate free actions for Redux")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/anish000kumar/redux-box"},"redux-box")," ",(0,n.kt)("em",{parentName:"li"},"Modular and easy-to-grasp redux based state management, with least boilerplate")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/jeffreyyoung/quick-redux"},"quick-redux")," ",(0,n.kt)("em",{parentName:"li"},"tools to make redux development quicker and easier")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/jamiebuilds/bey"},"bey")," ",(0,n.kt)("em",{parentName:"li"},"Simple immutable state for React using Immer")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/Maxvien/cool-store"},"cool-store")," ",(0,n.kt)("em",{parentName:"li"},"CoolStore is an immutable state store built on top of ImmerJS and RxJS")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/drcmda/immer-wieder#readme"},"immer-wieder")," ",(0,n.kt)("em",{parentName:"li"},"State management lib that combines React 16 Context and immer for Redux semantics")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/neurosnap/robodux"},"robodux")," ",(0,n.kt)("em",{parentName:"li"},"flexible way to reduce redux boilerplate")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/epeli/immer-reducer"},"immer-reducer")," ",(0,n.kt)("em",{parentName:"li"},"Type-safe and terse React (useReducer()) and Redux reducers with Typescript")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/knpwrs/redux-ts-utils"},"redux-ts-utils")," ",(0,n.kt)("em",{parentName:"li"},"Everything you need to create type-safe applications with Redux with a strong emphasis on simplicity")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/suchipi/react-state-tree"},"react-state-tree")," ",(0,n.kt)("em",{parentName:"li"},"Drop-in replacement for useState that persists your state into a redux-like state tree")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/salvoravida/redux-immer"},"redux-immer")," ",(0,n.kt)("em",{parentName:"li"},"is used to create an equivalent function of Redux combineReducers that works with ",(0,n.kt)("inlineCode",{parentName:"em"},"immer")," state. Like ",(0,n.kt)("inlineCode",{parentName:"em"},"redux-immutable")," but for ",(0,n.kt)("inlineCode",{parentName:"em"},"immer"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/nilsmehlhorn/ngrx-wieder"},"ngrx-wieder")," ",(0,n.kt)("em",{parentName:"li"},"Lightweight yet configurable solution for implementing undo-redo in Angular apps on top of NgRx and Immer")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/sep2/immer-yjs"},"immer-yjs")," ",(0,n.kt)("em",{parentName:"li"},"Combine ",(0,n.kt)("inlineCode",{parentName:"em"},"immer")," with CRDT library ",(0,n.kt)("inlineCode",{parentName:"em"},"y.js")," for easy json data manipulation")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/webstudio-is/immerhin"},"immerhin")," Sync state with undo/redo"),(0,n.kt)("li",{parentName:"ul"},"... and ",(0,n.kt)("a",{parentName:"li",href:"https://www.npmjs.com/browse/depended/immer"},"many more"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7956b02b.15560020.js b/assets/js/7956b02b.15560020.js new file mode 100644 index 00000000..a0a20d25 --- /dev/null +++ b/assets/js/7956b02b.15560020.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[91],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>u});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(r),f=a,u=p["".concat(c,".").concat(f)]||p[f]||m[f]||i;return r?n.createElement(u,o(o({ref:t},d),{},{components:r})):n.createElement(u,o({ref:t},d))}));function u(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=f;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>c,default:()=>f,frontMatter:()=>s,metadata:()=>l,toc:()=>p});var n=r(3117),a=r(102),i=(r(7294),r(3905)),o=["components"],s={id:"async",title:"createDraft / finishDraft",sidebar_label:"createDraft / finishDraft"},c=void 0,l={unversionedId:"async",id:"async",title:"createDraft / finishDraft",description:"createDraft and finishDraft",id:"createdraft-and-finishdraft",level:2}],m={toc:p};function f(e){var t=e.components,r=(0,a.Z)(e,o);return(0,i.kt)("wrapper",(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"}))," ",(0,i.kt)("details",null,(0,i.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 11: Creating ",(0,i.kt)("b",null,"async")," producers (and why you shouldn\u2019t)"),(0,i.kt)("br",null),(0,i.kt)("div",null,(0,i.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t/embed"})),(0,i.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t"},"Hosted on egghead.io")),(0,i.kt)("h2",{id:"createdraft-and-finishdraft"},(0,i.kt)("inlineCode",{parentName:"h2"},"createDraft")," and ",(0,i.kt)("inlineCode",{parentName:"h2"},"finishDraft")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"createDraft")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"finishDraft")," are two low-level functions that are mostly useful for libraries that build abstractions on top of immer. It avoids the need to always create a function in order to work with drafts. Instead, one can create a draft, modify it, and at some time in the future finish the draft, in which case the next immutable state will be produced."),(0,i.kt)("p",null,"Beyond that, ",(0,i.kt)("inlineCode",{parentName:"p"},"createDraft")," / ",(0,i.kt)("inlineCode",{parentName:"p"},"finishDraft")," could be used to express async updates to drafts:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'import {createDraft, finishDraft} from "immer"\n\nconst user = {\n name: "michel",\n todos: []\n}\n\nconst draft = createDraft(user)\ndraft.todos = await (await window.fetch("http://host/" + draft.name)).json()\nconst loadedUser = finishDraft(draft)\n')),(0,i.kt)("p",null,"Note: The above is an anti-pattern! First fetch data instead, then draft the ",(0,i.kt)("inlineCode",{parentName:"p"},"user"),'. Otherwise updates to user that happen during the async process, would be "missed" by the draft.'),(0,i.kt)("p",null,"Note: ",(0,i.kt)("inlineCode",{parentName:"p"},"finishDraft")," takes a ",(0,i.kt)("inlineCode",{parentName:"p"},"patchListener")," as second argument, which can be used to record the patches, similarly to ",(0,i.kt)("inlineCode",{parentName:"p"},"produce"),"."),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Warning: in general, we recommend to use ",(0,i.kt)("inlineCode",{parentName:"em"},"produce")," instead of the ",(0,i.kt)("inlineCode",{parentName:"em"},"createDraft")," / ",(0,i.kt)("inlineCode",{parentName:"em"},"finishDraft")," combo, ",(0,i.kt)("inlineCode",{parentName:"em"},"produce")," is less error prone in usage, and more clearly separates the concepts of mutability and immutability in your code base.")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/813ea2aa.8f6c63bf.js b/assets/js/813ea2aa.8f6c63bf.js new file mode 100644 index 00000000..e4c78f9d --- /dev/null +++ b/assets/js/813ea2aa.8f6c63bf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[484],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),f=a,m=u["".concat(c,".").concat(f)]||u[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>f,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var n=r(3117),a=r(102),o=(r(7294),r(3905)),i=["components"],l={id:"current",title:"Extracting the current state from a draft",sidebar_label:"Current"},c=void 0,s={unversionedId:"current",id:"current",title:"Extracting the current state from a draft",description:"Immer exposes a named export current that creates a copy of the current state of the draft. This can be very useful for debugging purposes (as those objects won't be Proxy objects and not be logged as such). Also, references to current can be safely leaked from a produce function. Put differently, current provides a snapshot of the current state of a draft.",source:"@site/docs/current.md",sourceDirName:".",slug:"/current",permalink:"/immer/current",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/current.md",tags:[],version:"current",frontMatter:{id:"current",title:"Extracting the current state from a draft",sidebar_label:"Current"},sidebar:"Immer",previous:{title:"Classes",permalink:"/immer/complex-objects"},next:{title:"Original",permalink:"/immer/original"}},p={},u=[{value:"Example",id:"example",level:3}],d={toc:u};function f(e){var t=e.components,r=(0,a.Z)(e,i);return(0,o.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("center",null,(0,o.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,o.kt)("p",null,"Immer exposes a named export ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," that creates a copy of the current state of the draft. This can be very useful for debugging purposes (as those objects won't be Proxy objects and not be logged as such). Also, references to ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," can be safely leaked from a produce function. Put differently, ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," provides a snapshot of the current state of a draft."),(0,o.kt)("p",null,"Objects generated by ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," work similar to the objects created by produce itself."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Unmodified objects will be structurally shared with the original objects."),(0,o.kt)("li",{parentName:"ol"},"If no changes are made to a draft, generally it holds that ",(0,o.kt)("inlineCode",{parentName:"li"},"original(draft) === current(draft)"),", but this is not guaranteed."),(0,o.kt)("li",{parentName:"ol"},"Future changes to the draft won't be reflected in the object produced by ",(0,o.kt)("inlineCode",{parentName:"li"},"current")," (except for references to undraftable objects)"),(0,o.kt)("li",{parentName:"ol"},"Unlike ",(0,o.kt)("inlineCode",{parentName:"li"},"produce")," objects created by ",(0,o.kt)("inlineCode",{parentName:"li"},"current")," will ",(0,o.kt)("em",{parentName:"li"},"not")," be frozen.")),(0,o.kt)("p",null,"Use ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," sparingly, it can be a potentially expensive operation, especially when using ES5."),(0,o.kt)("p",null,"Note that ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," cannot be invoked on objects that aren't drafts."),(0,o.kt)("h3",{id:"example"},"Example"),(0,o.kt)("p",null,"The following example shows the effect of ",(0,o.kt)("inlineCode",{parentName:"p"},"current")," (and ",(0,o.kt)("inlineCode",{parentName:"p"},"original"),"):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"const base = {\n x: 0\n}\n\nconst next = produce(base, draft => {\n draft.x++\n const orig = original(draft)\n const copy = current(draft)\n console.log(orig.x)\n console.log(copy.x)\n\n setTimeout(() => {\n // this will execute after the produce has finished!\n console.log(orig.x)\n console.log(copy.x)\n }, 100)\n\n draft.x++\n console.log(draft.x)\n})\nconsole.log(next.x)\n\n// This will print\n// 0 (orig.x)\n// 1 (copy.x)\n// 2 (draft.x)\n// 2 (next.x)\n// 0 (after timeout, orig.x)\n// 1 (after timeout, copy.x)\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/849404ec.f79a223b.js b/assets/js/849404ec.f79a223b.js new file mode 100644 index 00000000..d330911b --- /dev/null +++ b/assets/js/849404ec.f79a223b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[226],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),d=a,f=u["".concat(l,".").concat(d)]||u[d]||m[d]||i;return r?n.createElement(f,o(o({ref:t},p),{},{components:r})):n.createElement(f,o({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var n=r(3117),a=r(102),i=(r(7294),r(3905)),o=["components"],s={id:"original",title:"Extracting the original state from a draft",sidebar_label:"Original"},l=void 0,c={unversionedId:"original",id:"original",title:"Extracting the original state from a draft",description:"Immer exposes a named export original that will get the original object from the proxied instance inside produce (or return undefined for unproxied values). A good example of when this can be useful is when searching for nodes in a tree-like state using strict equality.",source:"@site/docs/original.md",sourceDirName:".",slug:"/original",permalink:"/immer/original",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/original.md",tags:[],version:"current",frontMatter:{id:"original",title:"Extracting the original state from a draft",sidebar_label:"Original"},sidebar:"Immer",previous:{title:"Current",permalink:"/immer/current"},next:{title:"Patches",permalink:"/immer/patches"}},p={},u=[],m={toc:u};function d(e){var t=e.components,r=(0,a.Z)(e,o);return(0,i.kt)("wrapper",(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,i.kt)("p",null,"Immer exposes a named export ",(0,i.kt)("inlineCode",{parentName:"p"},"original")," that will get the original object from the proxied instance inside ",(0,i.kt)("inlineCode",{parentName:"p"},"produce")," (or return ",(0,i.kt)("inlineCode",{parentName:"p"},"undefined")," for unproxied values). A good example of when this can be useful is when searching for nodes in a tree-like state using strict equality."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'import {original, produce} from "immer"\n\nconst baseState = {users: [{name: "Richie"}]}\nconst nextState = produce(baseState, draftState => {\n original(draftState.users) // is === baseState.users\n})\n')),(0,i.kt)("p",null,"Just want to know if a value is a proxied instance? Use the ",(0,i.kt)("inlineCode",{parentName:"p"},"isDraft")," function! Note that ",(0,i.kt)("inlineCode",{parentName:"p"},"original")," cannot be invoked on objects that aren't drafts."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'import {isDraft, produce} from "immer"\n\nconst baseState = {users: [{name: "Bobby"}]}\nconst nextState = produce(baseState, draft => {\n isDraft(draft) // => true\n isDraft(draft.users) // => true\n isDraft(draft.users[0]) // => true\n})\nisDraft(nextState) // => false\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.3ff6f6ed.js b/assets/js/935f2afb.3ff6f6ed.js new file mode 100644 index 00000000..d0d24a7b --- /dev/null +++ b/assets/js/935f2afb.3ff6f6ed.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"Immer":[{"type":"category","label":"Basics","items":[{"type":"link","label":"Introduction","href":"/immer/","docId":"introduction"},{"type":"link","label":"Installation","href":"/immer/installation","docId":"installation"},{"type":"link","label":"Using produce","href":"/immer/produce","docId":"produce"},{"type":"link","label":"Curried producers","href":"/immer/curried-produce","docId":"curried-produce"},{"type":"link","label":"React & Immer","href":"/immer/example-setstate","docId":"example-setstate"},{"type":"link","label":"Update patterns","href":"/immer/update-patterns","docId":"update-patterns"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Advanced Features","items":[{"type":"link","label":"API overview","href":"/immer/api","docId":"api"},{"type":"link","label":"Map and Set","href":"/immer/map-set","docId":"map-set"},{"type":"link","label":"Classes","href":"/immer/complex-objects","docId":"complex-objects"},{"type":"link","label":"Current","href":"/immer/current","docId":"current"},{"type":"link","label":"Original","href":"/immer/original","docId":"original"},{"type":"link","label":"Patches","href":"/immer/patches","docId":"patches"},{"type":"link","label":"Auto freezing","href":"/immer/freezing","docId":"freezing"},{"type":"link","label":"Returning new data from producers","href":"/immer/return","docId":"return"},{"type":"link","label":"createDraft / finishDraft","href":"/immer/async","docId":"async"},{"type":"link","label":"TypeScript / Flow","href":"/immer/typescript","docId":"typescript"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Resources","items":[{"type":"link","label":"Immer performance","href":"/immer/performance","docId":"performance"},{"type":"link","label":"External resources","href":"/immer/resources","docId":"resources"},{"type":"link","label":"FAQ","href":"/immer/faq","docId":"faq"},{"type":"link","label":"Pitfalls","href":"/immer/pitfalls","docId":"pitfalls"},{"type":"link","label":"Built with Immer","href":"/immer/built-with","docId":"built-with"},{"type":"link","label":"Supporting immer","href":"/immer/support","docId":"support"},{"type":"link","label":"Porting to other languages","href":"/immer/other-lang","docId":"other-lang"}],"collapsed":true,"collapsible":true}]},"docs":{"api":{"id":"api","title":"API overview","description":"| Exported name | Description | Section |","sidebar":"Immer"},"async":{"id":"async","title":"createDraft / finishDraft","description":"{n.r(t),n.d(t,{default:()=>i});var a=n(7294),l=n(5999),o=n(1944),r=n(7961);function i(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/assets/js/a09c2993.02efd803.js b/assets/js/a09c2993.02efd803.js new file mode 100644 index 00000000..5380a31d --- /dev/null +++ b/assets/js/a09c2993.02efd803.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[128],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),m=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=m(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=m(a),p=n,h=u["".concat(s,".").concat(p)]||u[p]||d[p]||i;return a?r.createElement(h,o(o({ref:t},c),{},{components:a})):r.createElement(h,o({ref:t},c))}));function h(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:n,o[1]=l;for(var m=2;m{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>p,frontMatter:()=>l,metadata:()=>m,toc:()=>u});var r=a(3117),n=a(102),i=(a(7294),a(3905)),o=["components"],l={id:"introduction",title:"Introduction to Immer",sidebar_label:"Introduction",slug:"/"},s=void 0,m={unversionedId:"introduction",id:"introduction",title:"Introduction to Immer",description:"Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.",source:"@site/docs/introduction.md",sourceDirName:".",slug:"/",permalink:"/immer/",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/introduction.md",tags:[],version:"current",frontMatter:{id:"introduction",title:"Introduction to Immer",sidebar_label:"Introduction",slug:"/"},sidebar:"Immer",next:{title:"Installation",permalink:"/immer/installation"}},c={},u=[{value:"Immer simplifies handling immutable data structures",id:"immer-simplifies-handling-immutable-data-structures",level:3},{value:"A quick example for comparison",id:"a-quick-example-for-comparison",level:3},{value:"Without Immer",id:"without-immer",level:4},{value:"With Immer",id:"with-immer",level:4},{value:"How Immer works",id:"how-immer-works",level:3},{value:"Benefits",id:"benefits",level:2}],d={toc:u};function p(e){var t=e.components,l=(0,n.Z)(e,o);return(0,i.kt)("wrapper",(0,r.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,i.kt)("img",{src:"/immer/img/immer-logo.svg",style:{maxHeight:200},align:"right"}),(0,i.kt)("h1",{id:"immer"},"Immer"),(0,i.kt)("p",null,"Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"Immer is life-changing as a JS dev, and I'm not even exaggerating :) Like, it's right up there with Prettier in terms of \"wow this package is amazing, how did I ever live without it?\" --Mark Erikson, (the) Redux Maintainer, @replayio")),(0,i.kt)("p",null,'Winner of the "Breakthrough of the year" ',(0,i.kt)("a",{parentName:"p",href:"https://osawards.com/react/"},"React open source award"),' and "Most impactful contribution" ',(0,i.kt)("a",{parentName:"p",href:"https://osawards.com/javascript/"},"JavaScript open source award")," in 2019."),(0,i.kt)("hr",null),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Introduction blogpost: ",(0,i.kt)("a",{parentName:"li",href:"https://medium.com/@mweststrate/introducing-immer-immutability-the-easy-way-9d73d8f71cb3"},"Immer: Immutability the easy way")),(0,i.kt)("li",{parentName:"ul"},"Short Egghead.io lesson covering the Immer essentials: ",(0,i.kt)("a",{parentName:"li",href:"https://egghead.io/lessons/redux-simplify-creating-immutable-data-trees-with-immer"},"Simplify creating immutable data trees with Immer (7m)")),(0,i.kt)("li",{parentName:"ul"},"Free in-depth Egghead.io course: ",(0,i.kt)("a",{parentName:"li",href:"https://egghead.io/courses/immutable-javascript-data-structures-with-immer"},"Immutable JavaScript Data Structures with Immer (58m)"))),(0,i.kt)("hr",null),(0,i.kt)("h3",{id:"immer-simplifies-handling-immutable-data-structures"},"Immer simplifies handling immutable data structures"),(0,i.kt)("p",null,"Immer can be used in any context in which immutable data structures need to be used. For example in combination with React state, React or Redux reducers, or configuration management. Immutable data structures allow for (efficient) change detection: if the reference to an object didn't change, the object itself did not change. In addition, it makes cloning relatively cheap: Unchanged parts of a data tree don't need to be copied and are shared in memory with older versions of the same state."),(0,i.kt)("p",null,"Generally speaking, these benefits can be achieved by making sure you never change any property of an object, array or map, but by always creating an altered copy instead. In practice this can result in code that is quite cumbersome to write, and it is easy to accidentally violate those constraints. Immer will help you to follow the immutable data paradigm by addressing these pain points:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Immer will detect accidental mutations and throw an error."),(0,i.kt)("li",{parentName:"ol"},"Immer will remove the need for the typical boilerplate code that is needed when creating deep updates to immutable objects: Without Immer, object copies need to be made by hand at every level. Typically by using a lot of ",(0,i.kt)("inlineCode",{parentName:"li"},"...")," spread operations. When using Immer, changes are made to a ",(0,i.kt)("inlineCode",{parentName:"li"},"draft")," object, that records the changes and takes care of creating the necessary copies, without ever affecting the original object."),(0,i.kt)("li",{parentName:"ol"},"When using Immer, you don't need to learn dedicated APIs or data structures to benefit from the paradigm. With Immer you'll use plain JavaScript data structures, and use the well-known mutable JavaScript APIs, but safely.")),(0,i.kt)("h3",{id:"a-quick-example-for-comparison"},"A quick example for comparison"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const baseState = [\n {\n title: "Learn TypeScript",\n done: true\n },\n {\n title: "Try Immer",\n done: false\n }\n]\n')),(0,i.kt)("p",null,"Imagine we have the above base state, and we'll need to update the second todo, and add a third one. However, we don't want to mutate the original ",(0,i.kt)("inlineCode",{parentName:"p"},"baseState"),", and we want to avoid deep cloning as well (to preserve the first todo)."),(0,i.kt)("h4",{id:"without-immer"},"Without Immer"),(0,i.kt)("p",null,"Without Immer, we'll have to carefully shallow copy every level of the state structure that is affected by our change:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const nextState = baseState.slice() // shallow clone the array\nnextState[1] = {\n // replace element 1...\n ...nextState[1], // with a shallow clone of element 1\n done: true // ...combined with the desired update\n}\n// since nextState was freshly cloned, using push is safe here,\n// but doing the same thing at any arbitrary time in the future would\n// violate the immutability principles and introduce a bug!\nnextState.push({title: "Tweet about it"})\n')),(0,i.kt)("h4",{id:"with-immer"},"With Immer"),(0,i.kt)("p",null,"With Immer, this process is more straightforward. We can leverage the ",(0,i.kt)("inlineCode",{parentName:"p"},"produce")," function, which takes as first argument the state we want to start from, and as second argument we pass a function, called the ",(0,i.kt)("em",{parentName:"p"},"recipe"),", that is passed a ",(0,i.kt)("inlineCode",{parentName:"p"},"draft")," to which we can apply straightforward mutations. Those mutations are recorded and used to produce the next state once the recipe is done. ",(0,i.kt)("inlineCode",{parentName:"p"},"produce")," will take care of all the necessary copying, and protect against future accidental modifications as well by freezing the data."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst nextState = produce(baseState, draft => {\n draft[1].done = true\n draft.push({title: "Tweet about it"})\n})\n')),(0,i.kt)("p",null,"Looking for Immer in combination with React? Feel free to skip ahead to the ",(0,i.kt)("a",{parentName:"p",href:"example-setstate"},"React + Immer")," page."),(0,i.kt)("h3",{id:"how-immer-works"},"How Immer works"),(0,i.kt)("p",null,"The basic idea is that with Immer you will apply all your changes to a temporary ",(0,i.kt)("em",{parentName:"p"},"draft"),", which is a proxy of the ",(0,i.kt)("em",{parentName:"p"},"currentState"),". Once all your mutations are completed, Immer will produce the ",(0,i.kt)("em",{parentName:"p"},"nextState")," based on the mutations to the draft state. This means that you can interact with your data by simply modifying it while keeping all the benefits of immutable data."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"immer-hd.png",src:a(9795).Z,width:"1400",height:"544"})),(0,i.kt)("p",null,"Using Immer is like having a personal assistant. The assistant takes a letter (the current state) and gives you a copy (draft) to jot changes onto. Once you are done, the assistant will take your draft and produce the real immutable, final letter for you (the next state)."),(0,i.kt)("p",null,"Head to the ",(0,i.kt)("a",{parentName:"p",href:"/immer/produce"},"next section")," to further dive into ",(0,i.kt)("inlineCode",{parentName:"p"},"produce"),"."),(0,i.kt)("h2",{id:"benefits"},"Benefits"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'Follow the immutable data paradigm, while using normal JavaScript objects, arrays, Sets and Maps. No new APIs or "mutation patterns" to learn!'),(0,i.kt)("li",{parentName:"ul"},"Strongly typed, no string based paths selectors etc."),(0,i.kt)("li",{parentName:"ul"},"Structural sharing out of the box"),(0,i.kt)("li",{parentName:"ul"},"Object freezing out of the box"),(0,i.kt)("li",{parentName:"ul"},"Deep updates are a breeze"),(0,i.kt)("li",{parentName:"ul"},"Boilerplate reduction. Less noise, more concise code."),(0,i.kt)("li",{parentName:"ul"},"First class support for JSON patches"),(0,i.kt)("li",{parentName:"ul"},"Small: 3KB gzipped")))}p.isMDXComponent=!0},9795:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png"}}]); \ No newline at end of file diff --git a/assets/js/aa829a7d.b3cc16e2.js b/assets/js/aa829a7d.b3cc16e2.js new file mode 100644 index 00000000..eff343ca --- /dev/null +++ b/assets/js/aa829a7d.b3cc16e2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[617],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},m=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=c(r),f=a,d=u["".concat(l,".").concat(f)]||u[f]||p[f]||i;return r?n.createElement(d,o(o({ref:t},m),{},{components:r})):n.createElement(d,o({ref:t},m))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>f,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var n=r(3117),a=r(102),i=(r(7294),r(3905)),o=["components"],s={id:"freezing",title:"Auto freezing"},l=void 0,c={unversionedId:"freezing",id:"freezing",title:"Auto freezing",description:"{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),d=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},l="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),l=d(r),m=o,f=l["".concat(c,".").concat(m)]||l[m]||u[m]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[l]="string"==typeof e?e:o,i[1]=p;for(var d=2;d{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>c,default:()=>m,frontMatter:()=>p,metadata:()=>d,toc:()=>l});var n=r(3117),o=r(102),a=(r(7294),r(3905)),i=["components"],p={id:"curried-produce",title:"Curried producers"},c=void 0,d={unversionedId:"curried-produce",id:"curried-produce",title:"Curried producers",description:" {\n const todo = draft.find(todo => todo.id === id)\n todo.done = !todo.done\n })\n}\n\nconst baseState = [\n {\n id: "JavaScript",\n title: "Learn TypeScript",\n done: true\n },\n {\n id: "Immer",\n title: "Try Immer",\n done: false\n }\n]\n\nconst nextState = toggleTodo(baseState, "Immer")\n')),(0,a.kt)("p",null,"The above pattern of ",(0,a.kt)("inlineCode",{parentName:"p"},"toggleTodo")," is quite typical; pass an existing state to ",(0,a.kt)("inlineCode",{parentName:"p"},"produce"),", modify the ",(0,a.kt)("inlineCode",{parentName:"p"},"draft"),", and then return the result. Since ",(0,a.kt)("inlineCode",{parentName:"p"},"state")," isn't used for anything else than passing it on to ",(0,a.kt)("inlineCode",{parentName:"p"},"produce"),", the above example can be simplified by using the ",(0,a.kt)("em",{parentName:"p"},"curried")," form of ",(0,a.kt)("inlineCode",{parentName:"p"},"produce"),", where you pass ",(0,a.kt)("inlineCode",{parentName:"p"},"produce")," only the recipe function, and ",(0,a.kt)("inlineCode",{parentName:"p"},"produce")," will return a new function that will apply recipe to the base state. This allows us to shorten the above ",(0,a.kt)("inlineCode",{parentName:"p"},"toggleTodo")," definition."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\n// curried producer:\nconst toggleTodo = produce((draft, id) => {\n const todo = draft.find(todo => todo.id === id)\n todo.done = !todo.done\n})\n\nconst baseState = [\n /* as is */\n]\n\nconst nextState = toggleTodo(baseState, "Immer")\n')),(0,a.kt)("p",null,"Note that the ",(0,a.kt)("inlineCode",{parentName:"p"},"id")," param has now become part of the recipe function! This pattern of having curried producers combines really neatly with for example the ",(0,a.kt)("inlineCode",{parentName:"p"},"useState")," hook from React, as we will see on the next page."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b1381a87.428452f4.js b/assets/js/b1381a87.428452f4.js new file mode 100644 index 00000000..40a96b30 --- /dev/null +++ b/assets/js/b1381a87.428452f4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[847],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>y});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),m=c(n),u=a,y=m["".concat(p,".").concat(u)]||m[u]||d[u]||i;return n?r.createElement(y,o(o({ref:t},l),{},{components:n})):r.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>p,default:()=>u,frontMatter:()=>s,metadata:()=>c,toc:()=>m});var r=n(3117),a=n(102),i=(n(7294),n(3905)),o=["components"],s={id:"map-set",title:"Map and Set"},p=void 0,c={unversionedId:"map-set",id:"map-set",title:"Map and Set",description:"\u26a0 Since version 6 support for Maps and Sets has to be enabled explicitly by calling enableMapSet() once when starting your application.",source:"@site/docs/map-set.md",sourceDirName:".",slug:"/map-set",permalink:"/immer/map-set",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/map-set.md",tags:[],version:"current",frontMatter:{id:"map-set",title:"Map and Set"},sidebar:"Immer",previous:{title:"API overview",permalink:"/immer/api"},next:{title:"Classes",permalink:"/immer/complex-objects"}},l={},m=[],d={toc:m};function u(e){var t=e.components,n=(0,a.Z)(e,o);return(0,i.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"\u26a0 Since version 6 support for ",(0,i.kt)("inlineCode",{parentName:"em"},"Map"),"s and ",(0,i.kt)("inlineCode",{parentName:"em"},"Set"),"s has to be enabled explicitly by calling ",(0,i.kt)("a",{parentName:"em",href:"/immer/installation#pick-your-immer-version"},(0,i.kt)("inlineCode",{parentName:"a"},"enableMapSet()"))," once when starting your application.")),(0,i.kt)("p",null,"Plain objects, arrays, ",(0,i.kt)("inlineCode",{parentName:"p"},"Map"),"s and ",(0,i.kt)("inlineCode",{parentName:"p"},"Set"),"s are always drafted by Immer. An example of using Maps with immer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'test("Producers can update Maps", () => {\n const usersById_v1 = new Map()\n\n const usersById_v2 = produce(usersById_v1, draft => {\n // Modifying a map results in a new map\n draft.set("michel", {name: "Michel Weststrate", country: "NL"})\n })\n\n const usersById_v3 = produce(usersById_v2, draft => {\n // Making a change deep inside a map, results in a new map as well!\n draft.get("michel").country = "UK"\n })\n\n // We got a new map each time!\n expect(usersById_v2).not.toBe(usersById_v1)\n expect(usersById_v3).not.toBe(usersById_v2)\n // With different content obviously\n expect(usersById_v1).toMatchInlineSnapshot(`Map {}`)\n expect(usersById_v2).toMatchInlineSnapshot(`\n Map {\n "michel" => Object {\n "country": "NL",\n "name": "Michel Weststrate",\n },\n }\n `)\n expect(usersById_v3).toMatchInlineSnapshot(`\n Map {\n "michel" => Object {\n "country": "UK",\n "name": "Michel Weststrate",\n },\n }\n `)\n // The old one was never modified\n expect(usersById_v1.size).toBe(0)\n // And trying to change a Map outside a producers is going to: NO!\n expect(() => usersById_v3.clear()).toThrowErrorMatchingInlineSnapshot(\n `"This object has been frozen and should not be mutated"`\n )\n})\n')),(0,i.kt)("p",null,"Maps and Sets that are produced by Immer will be made artificially immutable. This means that they will throw an exception when trying mutative methods like ",(0,i.kt)("inlineCode",{parentName:"p"},"set"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"clear")," etc. outside a producer."),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Note: The ",(0,i.kt)("strong",{parentName:"em"},"keys")," of a map are never drafted! This is done to avoid confusing semantics and keep keys always referentially equal")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bbcc1203.f9f2c60d.js b/assets/js/bbcc1203.f9f2c60d.js new file mode 100644 index 00000000..567c3001 --- /dev/null +++ b/assets/js/bbcc1203.f9f2c60d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[121],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>u});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),l=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),h=l(a),m=r,u=h["".concat(c,".").concat(m)]||h[m]||d[m]||s;return a?n.createElement(u,i(i({ref:t},p),{},{components:a})):n.createElement(u,i({ref:t},p))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=a.length,i=new Array(s);i[0]=m;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[h]="string"==typeof e?e:r,i[1]=o;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>h});var n=a(3117),r=a(102),s=(a(7294),a(3905)),i=["components"],o={id:"patches",title:"Patches"},c=void 0,l={unversionedId:"patches",id:"patches",title:"Patches",description:"produceWithPatches",id:"producewithpatches",level:3}],d={toc:h};function m(e){var t=e.components,a=(0,r.Z)(e,i);return(0,s.kt)("wrapper",(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("center",null,(0,s.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"}))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 14: Capture patches using _produceWithPatches_"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches"},"Hosted on egghead.io"))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 16: Apply Patches using _applyPatches_"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients"},"Hosted on egghead.io")),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"\u26a0 Since version 6 support for Patches has to be enabled explicitly by calling ",(0,s.kt)("a",{parentName:"em",href:"/immer/installation#pick-your-immer-version"},(0,s.kt)("inlineCode",{parentName:"a"},"enablePatches()"))," once when starting your application.")),(0,s.kt)("p",null,"During the run of a producer, Immer can record all the patches that would replay the changes made by the reducer. This is a very powerful tool if you want to fork your state temporarily and replay the changes to the original."),(0,s.kt)("p",null,"Patches are useful in few scenarios:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"To exchange incremental updates with other parties, for example over websockets"),(0,s.kt)("li",{parentName:"ul"},"For debugging / traces, to see precisely how state is changed over time"),(0,s.kt)("li",{parentName:"ul"},"As basis for undo/redo or as an approach to replay changes on a slightly different state tree")),(0,s.kt)("p",null,"To help with replaying patches, ",(0,s.kt)("inlineCode",{parentName:"p"},"applyPatches")," comes in handy. Here is an example how patches could be used to record the incremental updates and (inverse) apply them:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce, applyPatches} from "immer"\n\n// version 6\nimport {enablePatches} from "immer"\nenablePatches()\n\nlet state = {\n name: "Micheal",\n age: 32\n}\n\n// Let\'s assume the user is in a wizard, and we don\'t know whether\n// his changes should end up in the base state ultimately or not...\nlet fork = state\n// all the changes the user made in the wizard\nlet changes = []\n// the inverse of all the changes made in the wizard\nlet inverseChanges = []\n\nfork = produce(\n fork,\n draft => {\n draft.age = 33\n },\n // The third argument to produce is a callback to which the patches will be fed\n (patches, inversePatches) => {\n changes.push(...patches)\n inverseChanges.push(...inversePatches)\n }\n)\n\n// In the meantime, our original state is replaced, as, for example,\n// some changes were received from the server\nstate = produce(state, draft => {\n draft.name = "Michel"\n})\n\n// When the wizard finishes (successfully) we can replay the changes that were in the fork onto the *new* state!\nstate = applyPatches(state, changes)\n\n// state now contains the changes from both code paths!\nexpect(state).toEqual({\n name: "Michel", // changed by the server\n age: 33 // changed by the wizard\n})\n\n// Finally, even after finishing the wizard, the user might change his mind and undo his changes...\nstate = applyPatches(state, inverseChanges)\nexpect(state).toEqual({\n name: "Michel", // Not reverted\n age: 32 // Reverted\n})\n')),(0,s.kt)("p",null,"The generated patches are similar (but not the same) to the ",(0,s.kt)("a",{parentName:"p",href:"https://datatracker.ietf.org/doc/html/rfc6902/#section-4.1"},"RFC-6902 JSON patch standard"),", except that the ",(0,s.kt)("inlineCode",{parentName:"p"},"path")," property is an array, rather than a string. This makes processing patches easier. If you want to normalize to the official specification, ",(0,s.kt)("inlineCode",{parentName:"p"},'patch.path = patch.path.join("/")')," should do the trick. Anyway, this is what a bunch of patches and their inverse could look like:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "op": "replace",\n "path": ["profile"],\n "value": {"name": "Veria", "age": 5}\n },\n {"op": "remove", "path": ["tags", 3]}\n]\n')),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'[\n {"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},\n {"op": "add", "path": ["tags", 3], "value": "kiddo"}\n]\n')),(0,s.kt)("p",null,"\u26a0 Note: The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible. It depends often on the use case what is considered 'optimal', and generating the optimal set of patches is potentially computationally very expensive. So in cases you might want to post process the generated patches, or compress them as explained below."),(0,s.kt)("h3",{id:"producewithpatches"},(0,s.kt)("inlineCode",{parentName:"h3"},"produceWithPatches")),(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 19: Using inverse patches to build undo functionality"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality"},"Hosted on egghead.io"))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 20: Use patches to build redo functionality"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality"},"Hosted on egghead.io")),(0,s.kt)("p",null,"Instead of setting up a patch listener, an easier way to obtain the patches is to use ",(0,s.kt)("inlineCode",{parentName:"p"},"produceWithPatches"),", which has the same signature as ",(0,s.kt)("inlineCode",{parentName:"p"},"produce"),", except that it doesn't return just the next state, but a tuple consisting of ",(0,s.kt)("inlineCode",{parentName:"p"},"[nextState, patches, inversePatches]"),". Like ",(0,s.kt)("inlineCode",{parentName:"p"},"produce"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"produceWithPatches")," supports currying as well."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produceWithPatches} from "immer"\n\nconst [nextState, patches, inversePatches] = produceWithPatches(\n {\n age: 33\n },\n draft => {\n draft.age++\n }\n)\n')),(0,s.kt)("p",null,"Which produces:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'[\n {\n age: 34\n },\n [\n {\n op: "replace",\n path: ["age"],\n value: 34\n }\n ],\n [\n {\n op: "replace",\n path: ["age"],\n value: 33\n }\n ]\n]\n')),(0,s.kt)("p",null,"For a more in-depth study, see ",(0,s.kt)("a",{parentName:"p",href:"https://medium.com/@mweststrate/distributing-state-changes-using-snapshots-patches-and-actions-part-2-2f50d8363988"},"Distributing patches and rebasing actions using Immer")),(0,s.kt)("p",null,"Tip: Check this trick to ",(0,s.kt)("a",{parentName:"p",href:"https://medium.com/@david.b.edelstein/using-immer-to-compress-immer-patches-f382835b6c69"},"compress patches")," produced over time."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c31773f8.d9e3bf2a.js b/assets/js/c31773f8.d9e3bf2a.js new file mode 100644 index 00000000..668bd959 --- /dev/null +++ b/assets/js/c31773f8.d9e3bf2a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[83],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>y});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=s(n),u=a,y=c["".concat(p,".").concat(u)]||c[u]||m[u]||o;return n?r.createElement(y,i(i({ref:t},d),{},{components:n})):r.createElement(y,i({ref:t},d))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>p,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var r=n(3117),a=n(102),o=(n(7294),n(3905)),i=["components"],l={id:"typescript",title:"Using TypeScript or Flow",sidebar_label:"TypeScript / Flow"},p=void 0,s={unversionedId:"typescript",id:"typescript",title:"Using TypeScript or Flow",description:" {\n // `x` can be modified here\n draft.x++\n})\n\n// `newState.x` cannot be modified here\n')),(0,o.kt)("p",null,"This ensures that the only place you can modify your state is in your produce callbacks. It even works recursively and with ",(0,o.kt)("inlineCode",{parentName:"p"},"ReadonlyArray"),"."),(0,o.kt)("h2",{id:"best-practices"},"Best practices"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Always define your states as ",(0,o.kt)("inlineCode",{parentName:"li"},"readonly")," as much as possible. This best reflects the mental model and reality, since Immer will freeze all its returned values."),(0,o.kt)("li",{parentName:"ol"},"You can use the utility type ",(0,o.kt)("inlineCode",{parentName:"li"},"Immutable")," to recursively make an entire type tree read-only, e.g.: ",(0,o.kt)("inlineCode",{parentName:"li"},"type ReadonlyState = Immutable"),"."),(0,o.kt)("li",{parentName:"ol"},"Immer won't automatically wrap all returned types in ",(0,o.kt)("inlineCode",{parentName:"li"},"Immutable")," if the original type of the input state wasn't immutable. This is to make sure it doesn't break code bases that don't use immutable types.")),(0,o.kt)("h2",{id:"tips-for-curried-producers"},"Tips for curried producers"),(0,o.kt)("p",null,"We try to inference as much as possible. So if a curried producer is created and directly passed to another function, we can infer the type from there. This works well with for example React:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},'import {Immutable, produce} from "immer"\n\ntype Todo = Immutable<{\n title: string\n done: boolean\n}>\n\n// later...\n\nconst [todo, setTodo] = useState({\n title: "test",\n done: true\n})\n\n// later...\n\nsetTodo(\n produce(draft => {\n // draft will be strongly typed and mutable!\n draft.done = !draft.done\n })\n)\n')),(0,o.kt)("p",null,"When a curried producer isn't passed directly somewhere else, Immer can infer the state type from the draft argument. For example when doing the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"// See below for a better solution!\n\nconst toggler = produce((draft: Draft) => {\n draft.done = !draft.done\n})\n\n// typeof toggler = (state: Immutable) => Writable\n")),(0,o.kt)("p",null,"Note that we did wrap the ",(0,o.kt)("inlineCode",{parentName:"p"},"Todo")," type of the ",(0,o.kt)("inlineCode",{parentName:"p"},"draft")," argument with ",(0,o.kt)("inlineCode",{parentName:"p"},"Draft"),", because ",(0,o.kt)("inlineCode",{parentName:"p"},"Todo")," is a readonly type. For non-readonly types this isn't needed."),(0,o.kt)("p",null,"For the returned curried function, ",(0,o.kt)("inlineCode",{parentName:"p"},"toggler"),", We will ",(0,o.kt)("em",{parentName:"p"},"narrow")," the ",(0,o.kt)("em",{parentName:"p"},"input")," type to ",(0,o.kt)("inlineCode",{parentName:"p"},"Immutable"),", so that even though ",(0,o.kt)("inlineCode",{parentName:"p"},"Todo")," is a mutable type, we will still accept an immutable todo as input argument to ",(0,o.kt)("inlineCode",{parentName:"p"},"toggler"),"."),(0,o.kt)("p",null,"In contrast, Immer will ",(0,o.kt)("em",{parentName:"p"},"widen")," the ",(0,o.kt)("em",{parentName:"p"},"output")," type of the curried function to ",(0,o.kt)("inlineCode",{parentName:"p"},"Writable"),", to make sure it's output state is also assignable to variables that are not explictly typed to be immutable."),(0,o.kt)("p",null,"This type narrowing / widening behavior might be unwelcome, maybe even for the simple reason that it results in quite noisy types. So we recommend to specify the generic state type for curried producers instead, in cases where it cannot be inferred directly, like ",(0,o.kt)("inlineCode",{parentName:"p"},"toggler")," above. By doing so the automatic output widening / input narrowing will be skipped. However, the ",(0,o.kt)("inlineCode",{parentName:"p"},"draft")," argument itself will still be inferred to be a writable ",(0,o.kt)("inlineCode",{parentName:"p"},"Draft"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const toggler = produce(draft => {\n draft.done = !draft.done\n})\n\n// typeof toggler = (state: Todo) => Todo\n")),(0,o.kt)("p",null,"However, in case the curried producer is defined with an initial state, Immer can infer the state type from the initial state, so in that case the generic doesn't need to be specified either:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},'const state0: Todo = {\n title: "test",\n done: false\n}\n\n// No type annotations needed, since we can infer from state0.\nconst toggler = produce(draft => {\n draft.done = !draft.done\n}, state0)\n\n// typeof toggler = (state: Todo) => Todo\n')),(0,o.kt)("p",null,"In case the toggler has no initial state, and it has curried arguments, and you set the state generic explicitly, then type of any additional arguments should be defined explicitly as a tuple type as well:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const toggler = produce((draft, newState) => {\n draft.done = newState\n})\n\n// typeof toggler = (state: Todo, newState: boolean) => Todo\n")),(0,o.kt)("h2",{id:"cast-utilities"},"Cast utilities"),(0,o.kt)("p",null,"The types inside and outside a ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," can be conceptually the same, but from a practical perspective different. For example, the ",(0,o.kt)("inlineCode",{parentName:"p"},"State")," in the examples above should be considered immutable outside ",(0,o.kt)("inlineCode",{parentName:"p"},"produce"),", but mutable inside ",(0,o.kt)("inlineCode",{parentName:"p"},"produce"),"."),(0,o.kt)("p",null,"Sometimes this leads to practical conflicts. Take the following example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"type Todo = {readonly done: boolean}\n\ntype State = {\n readonly finishedTodos: readonly Todo[]\n readonly unfinishedTodos: readonly Todo[]\n}\n\nfunction markAllFinished(state: State) {\n produce(state, draft => {\n draft.finishedTodos = state.unfinishedTodos\n })\n}\n")),(0,o.kt)("p",null,"This will generate the error:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"The type 'readonly Todo[]' is 'readonly' and cannot be assigned to the mutable type '{ done: boolean; }[]'\n")),(0,o.kt)("p",null,"The reason for this error is that we assign our read only, immutable array to our draft, which expects a mutable type, with methods like ",(0,o.kt)("inlineCode",{parentName:"p"},".push")," etc etc. As far as TS is concerned, those are not exposed from our original ",(0,o.kt)("inlineCode",{parentName:"p"},"State"),". To hint TypeScript that we want to upcast the collection here to a mutable array for draft purposes, we can use the utility ",(0,o.kt)("inlineCode",{parentName:"p"},"castDraft"),":"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"draft.finishedTodos = castDraft(state.unfinishedTodos)")," will make the error disappear."),(0,o.kt)("p",null,"There is also the utility ",(0,o.kt)("inlineCode",{parentName:"p"},"castImmutable"),", in case you ever need to achieve the opposite. Note that these utilities are for all practical purposes no-ops, they will just return their original value."),(0,o.kt)("p",null,"Tip: You can combine ",(0,o.kt)("inlineCode",{parentName:"p"},"castImmutable")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," to type the return type of ",(0,o.kt)("inlineCode",{parentName:"p"},"produce")," as something immutable, even when the original state was mutable:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"// a mutable data structure\nconst baseState = {\n todos: [{\n done: false\n }]\n}\n\nconst nextState = castImmutable(produce(baseState, _draft => {}))\n\n// inferred type of nextState is now:\n{\n readonly todos: ReadonlyArray<{\n readonly done: boolean\n }>\n})\n")),(0,o.kt)("h2",{id:"compatibility"},"Compatibility"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note:")," Immer v5.3+ supports TypeScript v3.7+ only."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note:")," Immer v3.0+ supports TypeScript v3.4+ only."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note:")," Immer v1.9+ supports TypeScript v3.1+ only."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note:")," Flow support might be removed in future versions and we recommend TypeScript"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c73e0d38.f84bc059.js b/assets/js/c73e0d38.f84bc059.js new file mode 100644 index 00000000..76e7a360 --- /dev/null +++ b/assets/js/c73e0d38.f84bc059.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[247],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>b});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},m=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),p=c(r),d=o,b=p["".concat(l,".").concat(d)]||p[d]||u[d]||a;return r?n.createElement(b,i(i({ref:t},m),{},{components:r})):n.createElement(b,i({ref:t},m))}));function b(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var n=r(3117),o=r(102),a=(r(7294),r(3905)),i=["components"],s={id:"complex-objects",title:"Classes"},l=void 0,c={unversionedId:"complex-objects",id:"complex-objects",title:"Classes",description:"Plain objects (objects without a prototype), arrays, Maps and Sets are always drafted by Immer. Every other object must use the immerable symbol to mark itself as compatible with Immer. When one of these objects is mutated within a producer, its prototype is preserved between copies.",source:"@site/docs/complex-objects.md",sourceDirName:".",slug:"/complex-objects",permalink:"/immer/complex-objects",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/complex-objects.md",tags:[],version:"current",frontMatter:{id:"complex-objects",title:"Classes"},sidebar:"Immer",previous:{title:"Map and Set",permalink:"/immer/map-set"},next:{title:"Current",permalink:"/immer/current"}},m={},p=[{value:"Example",id:"example",level:3},{value:"Semantics in detail",id:"semantics-in-detail",level:3}],u={toc:p};function d(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("center",null,(0,a.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,a.kt)("p",null,"Plain objects (objects without a prototype), arrays, ",(0,a.kt)("inlineCode",{parentName:"p"},"Map"),"s and ",(0,a.kt)("inlineCode",{parentName:"p"},"Set"),"s are always drafted by Immer. Every other object must use the ",(0,a.kt)("inlineCode",{parentName:"p"},"immerable")," symbol to mark itself as compatible with Immer. When one of these objects is mutated within a producer, its prototype is preserved between copies."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'import {immerable} from "immer"\n\nclass Foo {\n [immerable] = true // Option 1\n\n constructor() {\n this[immerable] = true // Option 2\n }\n}\n\nFoo[immerable] = true // Option 3\n')),(0,a.kt)("h3",{id:"example"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},'import {immerable, produce} from "immer"\n\nclass Clock {\n [immerable] = true\n\n constructor(hour, minute) {\n this.hour = hour\n this.minute = minute\n }\n\n get time() {\n return `${this.hour}:${this.minute}`\n }\n\n tick() {\n return produce(this, draft => {\n draft.minute++\n })\n }\n}\n\nconst clock1 = new Clock(12, 10)\nconst clock2 = clock1.tick()\nconsole.log(clock1.time) // 12:10\nconsole.log(clock2.time) // 12:11\nconsole.log(clock2 instanceof Clock) // true\n')),(0,a.kt)("h3",{id:"semantics-in-detail"},"Semantics in detail"),(0,a.kt)("p",null,"The semantics on how classes are drafted are as follows:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"A draft of a class is a fresh object but with the same prototype as the original object."),(0,a.kt)("li",{parentName:"ol"},"When creating a draft, Immer will copy all ",(0,a.kt)("em",{parentName:"li"},"own")," properties from the base to the draft.This includes (in strict mode) non-enumerable and symbolic properties."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("em",{parentName:"li"},"Own")," getters will be invoked during the copy process, just like ",(0,a.kt)("inlineCode",{parentName:"li"},"Object.assign")," would."),(0,a.kt)("li",{parentName:"ol"},"Inherited getters and methods will remain as is and be inherited by the draft, as they are stored on the prototype which is untouched."),(0,a.kt)("li",{parentName:"ol"},"Immer will not invoke constructor functions."),(0,a.kt)("li",{parentName:"ol"},"The final instance will be constructed with the same mechanism as the draft was created."),(0,a.kt)("li",{parentName:"ol"},"Only getters that have a setter as well will be writable in the draft, as otherwise the value can't be copied back.")),(0,a.kt)("p",null,"Because Immer will dereference own getters of objects into normal properties, it is possible to use objects that use getter/setter traps on their fields, like MobX and Vue do."),(0,a.kt)("p",null,"Note that, by default, Immer does not strictly handle object's non-enumerable properties such as getters/setters for performance reason. If you want this behavior to be strict, you can opt-in with ",(0,a.kt)("inlineCode",{parentName:"p"},"useStrictShallowCopy(config)"),". Use ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," to always copy strict, or ",(0,a.kt)("inlineCode",{parentName:"p"},'"class_only"')," to only copy class instances strictly but use the faster loose copying for plain objects. The default is ",(0,a.kt)("inlineCode",{parentName:"p"},"false"),". (Remember, regardless of strict mode, own getters / setters are always copied ",(0,a.kt)("em",{parentName:"p"},"by value"),". There is currently no config to copy descriptors as-is. Feature request / PR welcome)."),(0,a.kt)("p",null,"Immer does not support exotic / engine native objects such as DOM Nodes or Buffers, nor is subclassing Map, Set or arrays supported and the ",(0,a.kt)("inlineCode",{parentName:"p"},"immerable")," symbol can't be used on them."),(0,a.kt)("p",null,"So when working for example with ",(0,a.kt)("inlineCode",{parentName:"p"},"Date")," objects, you should always create a new ",(0,a.kt)("inlineCode",{parentName:"p"},"Date")," instance instead of mutating an existing ",(0,a.kt)("inlineCode",{parentName:"p"},"Date")," object."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d92a3c43.9b4e1742.js b/assets/js/d92a3c43.9b4e1742.js new file mode 100644 index 00000000..d9a7aec5 --- /dev/null +++ b/assets/js/d92a3c43.9b4e1742.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[798],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>h});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),l=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,c=m(e,["components","mdxType","originalType","parentName"]),u=l(r),d=n,h=u["".concat(s,".").concat(d)]||u[d]||p[d]||i;return r?a.createElement(h,o(o({ref:t},c),{},{components:r})):a.createElement(h,o({ref:t},c))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=d;var m={};for(var s in t)hasOwnProperty.call(t,s)&&(m[s]=t[s]);m.originalType=e,m[u]="string"==typeof e?e:n,o[1]=m;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>m,metadata:()=>l,toc:()=>u});var a=r(3117),n=r(102),i=(r(7294),r(3905)),o=["components"],m={id:"resources",title:"External resources"},s=void 0,l={unversionedId:"resources",id:"resources",title:"External resources",description:"- Blog: The Rise of Immer in React",source:"@site/docs/resources.md",sourceDirName:".",slug:"/resources",permalink:"/immer/resources",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/resources.md",tags:[],version:"current",frontMatter:{id:"resources",title:"External resources"},sidebar:"Immer",previous:{title:"Immer performance",permalink:"/immer/performance"},next:{title:"FAQ",permalink:"/immer/faq"}},c={},u=[],p={toc:u};function d(e){var t=e.components,r=(0,n.Z)(e,o);return(0,i.kt)("wrapper",(0,a.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Blog: ",(0,i.kt)("a",{parentName:"li",href:"https://www.netlify.com/blog/2018/09/12/the-rise-of-immer-in-react/"},"The Rise of Immer in React")),(0,i.kt)("li",{parentName:"ul"},"Blog: by Workday Prism on why they picked Immer to manage immutable state ",(0,i.kt)("a",{parentName:"li",href:"https://medium.com/workday-engineering/workday-prism-analytics-the-search-for-a-strongly-typed-immutable-state-a09f6768b2b5"},"The Search for a Strongly-Typed, Immutable State")),(0,i.kt)("li",{parentName:"ul"},"Blog: ",(0,i.kt)("a",{parentName:"li",href:"https://daveceddia.com/react-redux-immutability-guide/"},"Immutability in React and Redux: The Complete Guide")),(0,i.kt)("li",{parentName:"ul"},"Video tutorial: ",(0,i.kt)("a",{parentName:"li",href:"https://codedaily.io/screencasts/86/Immutable-Data-with-Immer-and-React-setState"},"Using Immer with React.setState")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=-gJbS7YjcSo"},"Talk")," + ",(0,i.kt)("a",{parentName:"li",href:"http://immer.surge.sh/"},"slides")," on Immer at React Finland 2018 by Michel Weststrate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=bFuRvcAEiHg&feature=youtu.be"},"ForwardJS 2019: Immutability is Changing - From Immutable.js to Immer")," by ",(0,i.kt)("a",{parentName:"li",href:"https://twitter.com/swyx/"},"shawn swyx wang")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=4Nb9Gwp2L24"},"Talk: Immer, Immutability and the Wonderful World of Proxies")," + ",(0,i.kt)("a",{parentName:"li",href:"https://jsnation-proxies.surge.sh/"},"slides"),", JSNation 2019, Michel Weststrate"),(0,i.kt)("li",{parentName:"ul"},"Blog: ",(0,i.kt)("a",{parentName:"li",href:"https://medium.com/@mweststrate/distributing-state-changes-using-snapshots-patches-and-actions-part-1-2811a2fcd65f"},"Distributing state changes using snapshots, patches and actions")),(0,i.kt)("li",{parentName:"ul"},"Blog: ",(0,i.kt)("a",{parentName:"li",href:"https://techinscribed.com/implementing-undo-redo-functionality-in-redux-using-immer/"},"Implementing Undo-Redo Functionality in Redux"),", Sep 2019"),(0,i.kt)("li",{parentName:"ul"},"Blog: ",(0,i.kt)("a",{parentName:"li",href:"https://dev.to/oleg008/synchronized-immutable-state-with-time-travel-2c6o"},"Synchronized immutable state with time travel"),", Apr 2022, by ",(0,i.kt)("a",{parentName:"li",href:"https://twitter.com/oleg008"},"Oleg Isonen"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d9e16301.e2204e7e.js b/assets/js/d9e16301.e2204e7e.js new file mode 100644 index 00000000..f3cda7cb --- /dev/null +++ b/assets/js/d9e16301.e2204e7e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[217],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},m=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,m=p(e,["components","mdxType","originalType","parentName"]),c=s(r),d=o,f=c["".concat(l,".").concat(d)]||c[d]||u[d]||a;return r?n.createElement(f,i(i({ref:t},m),{},{components:r})):n.createElement(f,i({ref:t},m))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[c]="string"==typeof e?e:o,i[1]=p;for(var s=2;s{r.r(t),r.d(t,{assets:()=>m,contentTitle:()=>l,default:()=>d,frontMatter:()=>p,metadata:()=>s,toc:()=>c});var n=r(3117),o=r(102),a=(r(7294),r(3905)),i=["components"],p={id:"support",title:"Supporting immer"},l=void 0,s={unversionedId:"support",id:"support",title:"Supporting immer",description:"Immer currently has 350.000 dependents on GitHub, and has almost 10.000.000 downloads per month. However, only the first 2 days of development has been sponsored (by Mendix), and all the development and maintenance after that has been a labor of love.",source:"@site/docs/support.md",sourceDirName:".",slug:"/support",permalink:"/immer/support",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/support.md",tags:[],version:"current",frontMatter:{id:"support",title:"Supporting immer"},sidebar:"Immer",previous:{title:"Built with Immer",permalink:"/immer/built-with"},next:{title:"Porting to other languages",permalink:"/immer/other-lang"}},m={},c=[],u={toc:c};function d(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("center",null,(0,a.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"})),(0,a.kt)("p",null,"Immer currently has 350.000 dependents on GitHub, and has almost 10.000.000 downloads per month. However, only the first 2 days of development has been sponsored (by Mendix), and all the development and maintenance after that has been a labor of love."),(0,a.kt)("p",null,"If you are enjoying Immer, and you are grateful for the package, or want to ensure its longevity, consider sponsoring the open collective on ",(0,a.kt)("a",{parentName:"p",href:"https://opencollective.com/immer"},"https://opencollective.com/immer")," or make a one time donation using ",(0,a.kt)("a",{parentName:"p",href:"https://www.paypal.me/michelweststrate"},"PayPal"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e0b41884.5fb204d3.js b/assets/js/e0b41884.5fb204d3.js new file mode 100644 index 00000000..2dcd80b3 --- /dev/null +++ b/assets/js/e0b41884.5fb204d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[105],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var d=r.createContext({}),u=function(e){var t=r.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(d.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,f=c["".concat(d,".").concat(m)]||c[m]||p[m]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var d in t)hasOwnProperty.call(t,d)&&(s[d]=t[d]);s.originalType=e,s[c]="string"==typeof e?e:a,i[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>d,default:()=>m,frontMatter:()=>s,metadata:()=>u,toc:()=>c});var r=n(3117),a=n(102),o=(n(7294),n(3905)),i=["components"],s={id:"return",title:"Returning new data from producers"},d=void 0,u={unversionedId:"return",id:"return",title:"Returning new data from producers",description:"undefined using nothing",id:"producing-undefined-using-nothing",level:2},{value:"Inline shortcuts using void",id:"inline-shortcuts-using-void",level:2}],p={toc:c};function m(e){var t=e.components,n=(0,a.Z)(e,i);return(0,o.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("center",null,(0,o.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"}))," ",(0,o.kt)("details",null,(0,o.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 9: Returning completely new state"),(0,o.kt)("br",null),(0,o.kt)("div",null,(0,o.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-return-completely-new-state-from-an-immer-producer/embed"})),(0,o.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-return-completely-new-state-from-an-immer-producer"},"Hosted on egghead.io")),(0,o.kt)("p",null,"It is not needed to return anything from a producer, as Immer will return the (finalized) version of the ",(0,o.kt)("inlineCode",{parentName:"p"},"draft")," anyway. However, it is allowed to just ",(0,o.kt)("inlineCode",{parentName:"p"},"return draft"),"."),(0,o.kt)("p",null,"It is also allowed to return arbitrarily other data from the producer function. But ",(0,o.kt)("em",{parentName:"p"},"only")," if you didn't modify the draft. This can be useful to produce an entirely new state. Some examples:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const userReducer = produce((draft, action) => {\n switch (action.type) {\n case "renameUser":\n // OK: we modify the current state\n draft.users[action.payload.id].name = action.payload.name\n return draft // same as just \'return\'\n case "loadUsers":\n // OK: we return an entirely new state\n return action.payload\n case "adduser-1":\n // NOT OK: This doesn\'t do change the draft nor return a new state!\n // It doesn\'t modify the draft (it just redeclares it)\n // In fact, this just doesn\'t do anything at all\n draft = {users: [...draft.users, action.payload]}\n return\n case "adduser-2":\n // NOT OK: modifying draft *and* returning a new state\n draft.userCount += 1\n return {users: [...draft.users, action.payload]}\n case "adduser-3":\n // OK: returning a new state. But, unnecessary complex and expensive\n return {\n userCount: draft.userCount + 1,\n users: [...draft.users, action.payload]\n }\n case "adduser-4":\n // OK: the immer way\n draft.userCount += 1\n draft.users.push(action.payload)\n return\n }\n})\n')),(0,o.kt)("p",null,(0,o.kt)("em",{parentName:"p"},"Note: It is not possible to return ",(0,o.kt)("inlineCode",{parentName:"em"},"undefined")," this way, as it is indistinguishable from ",(0,o.kt)("em",{parentName:"em"},"not")," updating the draft! Read on...")),(0,o.kt)("h2",{id:"producing-undefined-using-nothing"},"Producing ",(0,o.kt)("inlineCode",{parentName:"h2"},"undefined")," using ",(0,o.kt)("inlineCode",{parentName:"h2"},"nothing")),(0,o.kt)("p",null,"So, in general, one can replace the current state by just ",(0,o.kt)("inlineCode",{parentName:"p"},"return"),"ing a new value from the producer, rather than modifying the draft. There is a subtle edge case however: if you try to write a producer that wants to replace the current state with ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},"produce({}, draft => {\n // don't do anything\n})\n")),(0,o.kt)("p",null,"Versus:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},"produce({}, draft => {\n // Try to return undefined from the producer\n return undefined\n})\n")),(0,o.kt)("p",null,"The problem is that in JavaScript a function that doesn't return anything also returns ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined"),"! So immer cannot differentiate between those different cases. So, by default, Immer will assume that any producer that returns ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," just tried to modify the draft."),(0,o.kt)("p",null,"However, to make it clear to Immer that you intentionally want to produce the value ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined"),", you can return the built-in token ",(0,o.kt)("inlineCode",{parentName:"p"},"nothing"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce, nothing} from "immer"\n\nconst state = {\n hello: "world"\n}\n\nproduce(state, draft => {})\nproduce(state, draft => undefined)\n// Both return the original state: { hello: "world"}\n\nproduce(state, draft => nothing)\n// Produces a new state, \'undefined\'\n')),(0,o.kt)("p",null,"N.B. Note that this problem is specific for the ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," value, any other value, including ",(0,o.kt)("inlineCode",{parentName:"p"},"null"),", doesn't suffer from this issue."),(0,o.kt)("p",null,"Tip: to be able to return ",(0,o.kt)("inlineCode",{parentName:"p"},"nothing")," from a recipe when using TypeScript, the ",(0,o.kt)("inlineCode",{parentName:"p"},"state"),"'s type must accept ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," as value."),(0,o.kt)("h2",{id:"inline-shortcuts-using-void"},"Inline shortcuts using ",(0,o.kt)("inlineCode",{parentName:"h2"},"void")),(0,o.kt)("details",null,(0,o.kt)("summary",{className:"egghead-summary"},"egghead.io lesson 10: Avoid accidental returns by using _void_"),(0,o.kt)("br",null),(0,o.kt)("div",null,(0,o.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-avoid-accidental-returns-of-new-state-by-using-the-void-keyword/embed"})),(0,o.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-avoid-accidental-returns-of-new-state-by-using-the-void-keyword"},"Hosted on egghead.io")),(0,o.kt)("p",null,"Draft mutations in Immer usually warrant a code block, since a return denotes an overwrite. Sometimes that can stretch code a little more than you might be comfortable with."),(0,o.kt)("p",null,"In such cases, you can use javascripts ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void"},(0,o.kt)("inlineCode",{parentName:"a"},"void"))," operator, which evaluates expressions and returns ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},"// Single mutation\nproduce(draft => void (draft.user.age += 1))\n\n// Multiple mutations\nproduce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))\n")),(0,o.kt)("p",null,"Code style is highly personal, but for code bases that are to be understood by many, we recommend to stick to the classic ",(0,o.kt)("inlineCode",{parentName:"p"},"draft => { draft.user.age += 1}")," to avoid cognitive overhead."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f6624ac6.7f4f4a6c.js b/assets/js/f6624ac6.7f4f4a6c.js new file mode 100644 index 00000000..c4de980b --- /dev/null +++ b/assets/js/f6624ac6.7f4f4a6c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[140],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/fa4d91bf.058e7ee8.js b/assets/js/fa4d91bf.058e7ee8.js new file mode 100644 index 00000000..01ee90b4 --- /dev/null +++ b/assets/js/fa4d91bf.058e7ee8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[930],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>k});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),m=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=m(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=m(n),d=a,k=c["".concat(p,".").concat(d)]||c[d]||u[d]||i;return n?r.createElement(k,o(o({ref:t},s),{},{components:n})):r.createElement(k,o({ref:t},s))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var m=2;m{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>m,toc:()=>c});var r=n(3117),a=n(102),i=(n(7294),n(3905)),o=["components"],l={id:"installation",title:"Installation"},p=void 0,m={unversionedId:"installation",id:"installation",title:"Installation",description:"<\/script>')),(0,i.kt)("li",{parentName:"ul"},"JSDelivr: ",(0,i.kt)("inlineCode",{parentName:"li"},' + + + + + + + + + + + + +
+

createDraft / finishDraft

egghead.io lesson 11: Creating async producers (and why you shouldn’t)

createDraft and finishDraft

createDraft and finishDraft are two low-level functions that are mostly useful for libraries that build abstractions on top of immer. It avoids the need to always create a function in order to work with drafts. Instead, one can create a draft, modify it, and at some time in the future finish the draft, in which case the next immutable state will be produced.

Beyond that, createDraft / finishDraft could be used to express async updates to drafts:

import {createDraft, finishDraft} from "immer"

const user = {
name: "michel",
todos: []
}

const draft = createDraft(user)
draft.todos = await (await window.fetch("http://host/" + draft.name)).json()
const loadedUser = finishDraft(draft)

Note: The above is an anti-pattern! First fetch data instead, then draft the user. Otherwise updates to user that happen during the async process, would be "missed" by the draft.

Note: finishDraft takes a patchListener as second argument, which can be used to record the patches, similarly to produce.

Warning: in general, we recommend to use produce instead of the createDraft / finishDraft combo, produce is less error prone in usage, and more clearly separates the concepts of mutability and immutability in your code base.

+ + + + \ No newline at end of file diff --git a/built-with/index.html b/built-with/index.html new file mode 100644 index 00000000..b198d686 --- /dev/null +++ b/built-with/index.html @@ -0,0 +1,26 @@ + + + + + +Built with Immer | Immer + + + + + + + + + + + + + + +
+

Built with Immer

  • react-copy-write Immutable state with a mutable API
  • redux-toolkit The official, opinionated, batteries-included toolset for efficient Redux development
  • immer based handleActions Boilerplate free actions for Redux
  • redux-box Modular and easy-to-grasp redux based state management, with least boilerplate
  • quick-redux tools to make redux development quicker and easier
  • bey Simple immutable state for React using Immer
  • cool-store CoolStore is an immutable state store built on top of ImmerJS and RxJS
  • immer-wieder State management lib that combines React 16 Context and immer for Redux semantics
  • robodux flexible way to reduce redux boilerplate
  • immer-reducer Type-safe and terse React (useReducer()) and Redux reducers with Typescript
  • redux-ts-utils Everything you need to create type-safe applications with Redux with a strong emphasis on simplicity
  • react-state-tree Drop-in replacement for useState that persists your state into a redux-like state tree
  • redux-immer is used to create an equivalent function of Redux combineReducers that works with immer state. Like redux-immutable but for immer
  • ngrx-wieder Lightweight yet configurable solution for implementing undo-redo in Angular apps on top of NgRx and Immer
  • immer-yjs Combine immer with CRDT library y.js for easy json data manipulation
  • immerhin Sync state with undo/redo
  • ... and many more
+ + + + \ No newline at end of file diff --git a/complex-objects/index.html b/complex-objects/index.html new file mode 100644 index 00000000..e0d45d18 --- /dev/null +++ b/complex-objects/index.html @@ -0,0 +1,26 @@ + + + + + +Classes | Immer + + + + + + + + + + + + + + +
+

Classes

Plain objects (objects without a prototype), arrays, Maps and Sets are always drafted by Immer. Every other object must use the immerable symbol to mark itself as compatible with Immer. When one of these objects is mutated within a producer, its prototype is preserved between copies.

import {immerable} from "immer"

class Foo {
[immerable] = true // Option 1

constructor() {
this[immerable] = true // Option 2
}
}

Foo[immerable] = true // Option 3

Example

import {immerable, produce} from "immer"

class Clock {
[immerable] = true

constructor(hour, minute) {
this.hour = hour
this.minute = minute
}

get time() {
return `${this.hour}:${this.minute}`
}

tick() {
return produce(this, draft => {
draft.minute++
})
}
}

const clock1 = new Clock(12, 10)
const clock2 = clock1.tick()
console.log(clock1.time) // 12:10
console.log(clock2.time) // 12:11
console.log(clock2 instanceof Clock) // true

Semantics in detail

The semantics on how classes are drafted are as follows:

  1. A draft of a class is a fresh object but with the same prototype as the original object.
  2. When creating a draft, Immer will copy all own properties from the base to the draft.This includes (in strict mode) non-enumerable and symbolic properties.
  3. Own getters will be invoked during the copy process, just like Object.assign would.
  4. Inherited getters and methods will remain as is and be inherited by the draft, as they are stored on the prototype which is untouched.
  5. Immer will not invoke constructor functions.
  6. The final instance will be constructed with the same mechanism as the draft was created.
  7. Only getters that have a setter as well will be writable in the draft, as otherwise the value can't be copied back.

Because Immer will dereference own getters of objects into normal properties, it is possible to use objects that use getter/setter traps on their fields, like MobX and Vue do.

Note that, by default, Immer does not strictly handle object's non-enumerable properties such as getters/setters for performance reason. If you want this behavior to be strict, you can opt-in with useStrictShallowCopy(config). Use true to always copy strict, or "class_only" to only copy class instances strictly but use the faster loose copying for plain objects. The default is false. (Remember, regardless of strict mode, own getters / setters are always copied by value. There is currently no config to copy descriptors as-is. Feature request / PR welcome).

Immer does not support exotic / engine native objects such as DOM Nodes or Buffers, nor is subclassing Map, Set or arrays supported and the immerable symbol can't be used on them.

So when working for example with Date objects, you should always create a new Date instance instead of mutating an existing Date object.

+ + + + \ No newline at end of file diff --git a/current/index.html b/current/index.html new file mode 100644 index 00000000..f4b1b25d --- /dev/null +++ b/current/index.html @@ -0,0 +1,26 @@ + + + + + +Extracting the current state from a draft | Immer + + + + + + + + + + + + + + +
+

Extracting the current state from a draft

Immer exposes a named export current that creates a copy of the current state of the draft. This can be very useful for debugging purposes (as those objects won't be Proxy objects and not be logged as such). Also, references to current can be safely leaked from a produce function. Put differently, current provides a snapshot of the current state of a draft.

Objects generated by current work similar to the objects created by produce itself.

  1. Unmodified objects will be structurally shared with the original objects.
  2. If no changes are made to a draft, generally it holds that original(draft) === current(draft), but this is not guaranteed.
  3. Future changes to the draft won't be reflected in the object produced by current (except for references to undraftable objects)
  4. Unlike produce objects created by current will not be frozen.

Use current sparingly, it can be a potentially expensive operation, especially when using ES5.

Note that current cannot be invoked on objects that aren't drafts.

Example

The following example shows the effect of current (and original):

const base = {
x: 0
}

const next = produce(base, draft => {
draft.x++
const orig = original(draft)
const copy = current(draft)
console.log(orig.x)
console.log(copy.x)

setTimeout(() => {
// this will execute after the produce has finished!
console.log(orig.x)
console.log(copy.x)
}, 100)

draft.x++
console.log(draft.x)
})
console.log(next.x)

// This will print
// 0 (orig.x)
// 1 (copy.x)
// 2 (draft.x)
// 2 (next.x)
// 0 (after timeout, orig.x)
// 1 (after timeout, copy.x)
+ + + + \ No newline at end of file diff --git a/curried-produce/index.html b/curried-produce/index.html new file mode 100644 index 00000000..a2d55111 --- /dev/null +++ b/curried-produce/index.html @@ -0,0 +1,26 @@ + + + + + +Curried producers | Immer + + + + + + + + + + + + + + +
+

Curried producers

egghead.io lesson 6: Simplify code by using curried _reduce_

Passing a function as the first argument to produce creates a function that doesn't apply produce yet to a specific state, but rather creates a function that will apply produce to any state that is passed to it in the future. This generally is called currying. Take for example the following example:

import {produce} from "immer"

function toggleTodo(state, id) {
return produce(state, draft => {
const todo = draft.find(todo => todo.id === id)
todo.done = !todo.done
})
}

const baseState = [
{
id: "JavaScript",
title: "Learn TypeScript",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]

const nextState = toggleTodo(baseState, "Immer")

The above pattern of toggleTodo is quite typical; pass an existing state to produce, modify the draft, and then return the result. Since state isn't used for anything else than passing it on to produce, the above example can be simplified by using the curried form of produce, where you pass produce only the recipe function, and produce will return a new function that will apply recipe to the base state. This allows us to shorten the above toggleTodo definition.

import {produce} from "immer"

// curried producer:
const toggleTodo = produce((draft, id) => {
const todo = draft.find(todo => todo.id === id)
todo.done = !todo.done
})

const baseState = [
/* as is */
]

const nextState = toggleTodo(baseState, "Immer")

Note that the id param has now become part of the recipe function! This pattern of having curried producers combines really neatly with for example the useState hook from React, as we will see on the next page.

+ + + + \ No newline at end of file diff --git a/docs/404.html/index.html b/docs/404.html/index.html new file mode 100644 index 00000000..f362b1ab --- /dev/null +++ b/docs/404.html/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/api/index.html b/docs/api/index.html new file mode 100644 index 00000000..18708c84 --- /dev/null +++ b/docs/api/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/async/index.html b/docs/async/index.html new file mode 100644 index 00000000..67c7f09d --- /dev/null +++ b/docs/async/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/built-with/index.html b/docs/built-with/index.html new file mode 100644 index 00000000..abb58237 --- /dev/null +++ b/docs/built-with/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/complex-objects/index.html b/docs/complex-objects/index.html new file mode 100644 index 00000000..4d698538 --- /dev/null +++ b/docs/complex-objects/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/current/index.html b/docs/current/index.html new file mode 100644 index 00000000..29a4a2a3 --- /dev/null +++ b/docs/current/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/curried-produce/index.html b/docs/curried-produce/index.html new file mode 100644 index 00000000..b5a2a3cc --- /dev/null +++ b/docs/curried-produce/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/example-setstate/index.html b/docs/example-setstate/index.html new file mode 100644 index 00000000..d0c9981b --- /dev/null +++ b/docs/example-setstate/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/faq/index.html b/docs/faq/index.html new file mode 100644 index 00000000..9e4ba396 --- /dev/null +++ b/docs/faq/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/freezing/index.html b/docs/freezing/index.html new file mode 100644 index 00000000..da30e5ab --- /dev/null +++ b/docs/freezing/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..cc0e0c6c --- /dev/null +++ b/docs/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/installation/index.html b/docs/installation/index.html new file mode 100644 index 00000000..d9569fda --- /dev/null +++ b/docs/installation/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/map-set/index.html b/docs/map-set/index.html new file mode 100644 index 00000000..8aa1912f --- /dev/null +++ b/docs/map-set/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/original/index.html b/docs/original/index.html new file mode 100644 index 00000000..69370697 --- /dev/null +++ b/docs/original/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/other-lang/index.html b/docs/other-lang/index.html new file mode 100644 index 00000000..812da8fe --- /dev/null +++ b/docs/other-lang/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/patches/index.html b/docs/patches/index.html new file mode 100644 index 00000000..1be66f9e --- /dev/null +++ b/docs/patches/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/performance/index.html b/docs/performance/index.html new file mode 100644 index 00000000..7d646020 --- /dev/null +++ b/docs/performance/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/pitfalls/index.html b/docs/pitfalls/index.html new file mode 100644 index 00000000..1d88e92f --- /dev/null +++ b/docs/pitfalls/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/produce/index.html b/docs/produce/index.html new file mode 100644 index 00000000..da1153a0 --- /dev/null +++ b/docs/produce/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/resources/index.html b/docs/resources/index.html new file mode 100644 index 00000000..8848913e --- /dev/null +++ b/docs/resources/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/return/index.html b/docs/return/index.html new file mode 100644 index 00000000..95992d79 --- /dev/null +++ b/docs/return/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/support/index.html b/docs/support/index.html new file mode 100644 index 00000000..af80b153 --- /dev/null +++ b/docs/support/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/index.html b/docs/typescript/index.html new file mode 100644 index 00000000..247f2bde --- /dev/null +++ b/docs/typescript/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/update-patterns/index.html b/docs/update-patterns/index.html new file mode 100644 index 00000000..3f1af238 --- /dev/null +++ b/docs/update-patterns/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/example-setstate/index.html b/example-setstate/index.html new file mode 100644 index 00000000..a93f362e --- /dev/null +++ b/example-setstate/index.html @@ -0,0 +1,26 @@ + + + + + +React & Immer | Immer + + + + + + + + + + + + + + +
+

React & Immer

egghead.io lesson 8: Using Immer with _useState_. Or: _useImmer_

useState + Immer

The useState hook assumes any state that is stored inside it is treated as immutable. Deep updates in the state of React components can be greatly simplified as by using Immer. The following example shows how to use produce in combination with useState, and can be tried on CodeSandbox.

import React, { useCallback, useState } from "react";
import {produce} from "immer";

const TodoList = () => {
const [todos, setTodos] = useState([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);

const handleToggle = useCallback((id) => {
setTodos(
produce((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
})
);
}, []);

const handleAdd = useCallback(() => {
setTodos(
produce((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
})
);
}, []);

return (<div>{*/ See CodeSandbox */}</div>)
}

useImmer

Since all state updaters follow the same pattern where the update function is wrapped in produce, it is also possible to simplify the above by leveraging the use-immer package that will wrap updater functions in produce automatically:

import React, { useCallback } from "react";
import { useImmer } from "use-immer";

const TodoList = () => {
const [todos, setTodos] = useImmer([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);

const handleToggle = useCallback((id) => {
setTodos((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
});
}, []);

const handleAdd = useCallback(() => {
setTodos((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
});
}, []);

// etc

For the full demo see CodeSandbox.

useReducer + Immer

Similarly to useState, useReducer combines neatly with Immer as well, as demonstrated in this CodeSandbox:

import React, {useCallback, useReducer} from "react"
import {produce} from "immer"

const TodoList = () => {
const [todos, dispatch] = useReducer(
produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
}),
[
/* initial todos */
]
)

const handleToggle = useCallback(id => {
dispatch({
type: "toggle",
id
})
}, [])

const handleAdd = useCallback(() => {
dispatch({
type: "add",
id: "todo_" + Math.random()
})
}, [])

// etc
}

useImmerReducer

...which again, can be slightly shorted by useImmerReducer from the use-immer package (demo):

import React, { useCallback } from "react";
import { useImmerReducer } from "use-immer";

const TodoList = () => {
const [todos, dispatch] = useImmerReducer(
(draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find((todo) => todo.id === action.id);
todo.done = !todo.done;
break;
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
});
break;
default:
break;
}
},
[ /* initial todos */ ]
);

//etc

Redux + Immer

Redux + Immer is extensively covered in the documentation of Redux Toolkit. For Redux without Redux Toolkit, the same trick as applied to useReducer above can be applied: wrap the reducer function with produce, and you can safely mutate the draft!

For example:

import {produce} from "immer"

// Reducer with initial state
const INITIAL_STATE = [
/* bunch of todos */
]

const todosReducer = produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
})
+ + + + \ No newline at end of file diff --git a/faq/index.html b/faq/index.html new file mode 100644 index 00000000..913e2016 --- /dev/null +++ b/faq/index.html @@ -0,0 +1,26 @@ + + + + + +Frequently Asked Questions | Immer + + + + + + + + + + + + + + +
+

Frequently Asked Questions

Q: How does Immer work?

Read the (second part of the) introduction blog.

Q: Does Immer use structural sharing? So that my selectors can be memoized and such?

A: Yes

Q: Does Immer support deep updates?

A: Yes

Q: I can't rely on Proxies being present on my target environments. Can I use Immer?

A: Yes - view details

Q: Can I typecheck my data structures when using Immer?

A: Yes

Q: Can I store Date objects, functions etc in my state tree when using Immer?

A: Yes

Q: Can I use Maps and Sets?

A: Yes

Q: Is it fast?

A: Yes

Q: Idea! Can Immer freeze the state for me?

A: Yes

+ + + + \ No newline at end of file diff --git a/freezing/index.html b/freezing/index.html new file mode 100644 index 00000000..3821b63f --- /dev/null +++ b/freezing/index.html @@ -0,0 +1,26 @@ + + + + + +Auto freezing | Immer + + + + + + + + + + + + + + +
+

Auto freezing

egghead.io lesson 7: Immer automatically freezes data

Immer automatically freezes any state trees that are modified using produce. This protects against accidental modifications of the state tree outside of a producer. In most cases this provides the most optimal behavior, but setAutoFreeze(true / false) can be used to explicitly turn this feature on or off.

Immer will never freeze (the contents of) non-enumerable, non-own or symbolic properties, unless their content was drafted.

⚠️ Immer freezes everything recursively, for large data objects that won't be changed in the future this might be over-kill, in that case it can be more efficient to shallowly pre-freeze data using the freeze utility.⚠️

⚠️ If auto freezing is enabled, recipes are not entirely side-effect free: Any plain object or array that ends up in the produced result, will be frozen, even when these objects were not frozen before the start of the producer! ⚠️

+ + + + \ No newline at end of file diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 00000000..272e0837 Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/immer-logo.png b/img/immer-logo.png new file mode 100644 index 00000000..9a7221e2 Binary files /dev/null and b/img/immer-logo.png differ diff --git a/img/immer-logo.svg b/img/immer-logo.svg new file mode 100644 index 00000000..da42bc8d --- /dev/null +++ b/img/immer-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/img/immer.png b/img/immer.png new file mode 100644 index 00000000..c83185f8 Binary files /dev/null and b/img/immer.png differ diff --git a/img/performance.png b/img/performance.png new file mode 100644 index 00000000..1fd5c8be Binary files /dev/null and b/img/performance.png differ diff --git a/img/proxy.png b/img/proxy.png new file mode 100644 index 00000000..8a4312e8 Binary files /dev/null and b/img/proxy.png differ diff --git a/img/tree.png b/img/tree.png new file mode 100644 index 00000000..eefa2234 Binary files /dev/null and b/img/tree.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..a1e4b339 --- /dev/null +++ b/index.html @@ -0,0 +1,26 @@ + + + + + +Introduction to Immer | Immer + + + + + + + + + + + + + + +
+

Introduction to Immer

Immer

Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.

Immer is life-changing as a JS dev, and I'm not even exaggerating :) Like, it's right up there with Prettier in terms of "wow this package is amazing, how did I ever live without it?" --Mark Erikson, (the) Redux Maintainer, @replayio

Winner of the "Breakthrough of the year" React open source award and "Most impactful contribution" JavaScript open source award in 2019.



Immer simplifies handling immutable data structures

Immer can be used in any context in which immutable data structures need to be used. For example in combination with React state, React or Redux reducers, or configuration management. Immutable data structures allow for (efficient) change detection: if the reference to an object didn't change, the object itself did not change. In addition, it makes cloning relatively cheap: Unchanged parts of a data tree don't need to be copied and are shared in memory with older versions of the same state.

Generally speaking, these benefits can be achieved by making sure you never change any property of an object, array or map, but by always creating an altered copy instead. In practice this can result in code that is quite cumbersome to write, and it is easy to accidentally violate those constraints. Immer will help you to follow the immutable data paradigm by addressing these pain points:

  1. Immer will detect accidental mutations and throw an error.
  2. Immer will remove the need for the typical boilerplate code that is needed when creating deep updates to immutable objects: Without Immer, object copies need to be made by hand at every level. Typically by using a lot of ... spread operations. When using Immer, changes are made to a draft object, that records the changes and takes care of creating the necessary copies, without ever affecting the original object.
  3. When using Immer, you don't need to learn dedicated APIs or data structures to benefit from the paradigm. With Immer you'll use plain JavaScript data structures, and use the well-known mutable JavaScript APIs, but safely.

A quick example for comparison

const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]

Imagine we have the above base state, and we'll need to update the second todo, and add a third one. However, we don't want to mutate the original baseState, and we want to avoid deep cloning as well (to preserve the first todo).

Without Immer

Without Immer, we'll have to carefully shallow copy every level of the state structure that is affected by our change:

const nextState = baseState.slice() // shallow clone the array
nextState[1] = {
// replace element 1...
...nextState[1], // with a shallow clone of element 1
done: true // ...combined with the desired update
}
// since nextState was freshly cloned, using push is safe here,
// but doing the same thing at any arbitrary time in the future would
// violate the immutability principles and introduce a bug!
nextState.push({title: "Tweet about it"})

With Immer

With Immer, this process is more straightforward. We can leverage the produce function, which takes as first argument the state we want to start from, and as second argument we pass a function, called the recipe, that is passed a draft to which we can apply straightforward mutations. Those mutations are recorded and used to produce the next state once the recipe is done. produce will take care of all the necessary copying, and protect against future accidental modifications as well by freezing the data.

import {produce} from "immer"

const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})

Looking for Immer in combination with React? Feel free to skip ahead to the React + Immer page.

How Immer works

The basic idea is that with Immer you will apply all your changes to a temporary draft, which is a proxy of the currentState. Once all your mutations are completed, Immer will produce the nextState based on the mutations to the draft state. This means that you can interact with your data by simply modifying it while keeping all the benefits of immutable data.

immer-hd.png

Using Immer is like having a personal assistant. The assistant takes a letter (the current state) and gives you a copy (draft) to jot changes onto. Once you are done, the assistant will take your draft and produce the real immutable, final letter for you (the next state).

Head to the next section to further dive into produce.

Benefits

  • Follow the immutable data paradigm, while using normal JavaScript objects, arrays, Sets and Maps. No new APIs or "mutation patterns" to learn!
  • Strongly typed, no string based paths selectors etc.
  • Structural sharing out of the box
  • Object freezing out of the box
  • Deep updates are a breeze
  • Boilerplate reduction. Less noise, more concise code.
  • First class support for JSON patches
  • Small: 3KB gzipped
+ + + + \ No newline at end of file diff --git a/installation/index.html b/installation/index.html new file mode 100644 index 00000000..85084c2d --- /dev/null +++ b/installation/index.html @@ -0,0 +1,26 @@ + + + + + +Installation | Immer + + + + + + + + + + + + + + +
+

Installation

Immer can be installed as a direct dependency, and will work in any ES5 environment:

  • Yarn: yarn add immer
  • NPM: npm install immer
  • CDN: Exposed global is immer
    • Unpkg: <script src="https://unpkg.com/immer"></script>
    • JSDelivr: <script src="https://cdn.jsdelivr.net/npm/immer"></script>
    • ⚠️ When using a CDN, it is best to check the url in your browser and see what version it resolves to, so that your users aren't accidentally served a newer version in the future when updates are release. So use a url like: https://unpkg.com/immer@6.0.3/dist/immer.umd.production.min.js instead. Substitute production.min with development in the URL for a development build.

Pick your Immer version

This section only applies to version 6 and later

To make sure Immer is as small as possible, features that are not required by every project has been made opt-in, and have to be enabled explicitly. This ensures that when bundling your application for production, unused features don't take any space.

The following features can be opt-in to:

FeatureDescriptionMethod to call
ES2015 Map and Set supportTo enable Immer to operate on the native Map and Set collections, enable this featureenableMapSet()
JSON Patch supportImmer can keep track of all the changes you make to draft objects. This can be useful for communicating changes using JSON patchesenablePatches()

For example, if you want to use produce on a Map, you need to enable this feature once during the start of your application:

// In your application's entrypoint
import {enableMapSet} from "immer"

enableMapSet()

// ...later
import {produce} from "immer"

const usersById_v1 = new Map([
["michel", {name: "Michel Weststrate", country: "NL"}]
])

const usersById_v2 = produce(usersById_v1, draft => {
draft.get("michel").country = "UK"
})

expect(usersById_v1.get("michel").country).toBe("NL")
expect(usersById_v2.get("michel").country).toBe("UK")

Vanilla Immer kicks in at ~3KB gzipped. Every plugin that is enabled adds < 1 KB to that. The breakdown is as follows:

Import size report for immer:
┌───────────────────────┬───────────┬────────────┬───────────┐
│ (index) │ just this │ cumulative │ increment │
├───────────────────────┼───────────┼────────────┼───────────┤
│ import * from 'immer' │ 5033 │ 0 │ 0 │
│ produce │ 3324 │ 3324 │ 0 │
│ enableMapSet │ 4030 │ 4039 │ 715 │
│ enablePatches │ 4112 │ 4826 │ 787 │
└───────────────────────┴───────────┴────────────┴───────────┘
(this report was generated by npmjs.com/package/import-size)

Immer on older JavaScript environments?

By default produce tries to use proxies for optimal performance. However, on older JavaScript engines Proxy is not available. For example, when running Microsoft Internet Explorer or React Native (if < v0.59 or when using the Hermes engine on React Native < 0.64) on Android. In such cases, Immer will fallback to an ES5 compatible implementation which works identically, but is a bit slower.

  • Since version 6, support for the fallback implementation has to be explicitly enabled by calling enableES5().
  • Version 10 drops the fallback implementation fully, and cannot be used in browsers / engines that don't support Proxy.
+ + + + \ No newline at end of file diff --git a/map-set/index.html b/map-set/index.html new file mode 100644 index 00000000..6a0238dc --- /dev/null +++ b/map-set/index.html @@ -0,0 +1,26 @@ + + + + + +Map and Set | Immer + + + + + + + + + + + + + + +
+

Map and Set

⚠ Since version 6 support for Maps and Sets has to be enabled explicitly by calling enableMapSet() once when starting your application.

Plain objects, arrays, Maps and Sets are always drafted by Immer. An example of using Maps with immer:

test("Producers can update Maps", () => {
const usersById_v1 = new Map()

const usersById_v2 = produce(usersById_v1, draft => {
// Modifying a map results in a new map
draft.set("michel", {name: "Michel Weststrate", country: "NL"})
})

const usersById_v3 = produce(usersById_v2, draft => {
// Making a change deep inside a map, results in a new map as well!
draft.get("michel").country = "UK"
})

// We got a new map each time!
expect(usersById_v2).not.toBe(usersById_v1)
expect(usersById_v3).not.toBe(usersById_v2)
// With different content obviously
expect(usersById_v1).toMatchInlineSnapshot(`Map {}`)
expect(usersById_v2).toMatchInlineSnapshot(`
Map {
"michel" => Object {
"country": "NL",
"name": "Michel Weststrate",
},
}
`)
expect(usersById_v3).toMatchInlineSnapshot(`
Map {
"michel" => Object {
"country": "UK",
"name": "Michel Weststrate",
},
}
`)
// The old one was never modified
expect(usersById_v1.size).toBe(0)
// And trying to change a Map outside a producers is going to: NO!
expect(() => usersById_v3.clear()).toThrowErrorMatchingInlineSnapshot(
`"This object has been frozen and should not be mutated"`
)
})

Maps and Sets that are produced by Immer will be made artificially immutable. This means that they will throw an exception when trying mutative methods like set, clear etc. outside a producer.

Note: The keys of a map are never drafted! This is done to avoid confusing semantics and keep keys always referentially equal

+ + + + \ No newline at end of file diff --git a/original/index.html b/original/index.html new file mode 100644 index 00000000..28bc51c8 --- /dev/null +++ b/original/index.html @@ -0,0 +1,26 @@ + + + + + +Extracting the original state from a draft | Immer + + + + + + + + + + + + + + +
+

Extracting the original state from a draft

Immer exposes a named export original that will get the original object from the proxied instance inside produce (or return undefined for unproxied values). A good example of when this can be useful is when searching for nodes in a tree-like state using strict equality.

import {original, produce} from "immer"

const baseState = {users: [{name: "Richie"}]}
const nextState = produce(baseState, draftState => {
original(draftState.users) // is === baseState.users
})

Just want to know if a value is a proxied instance? Use the isDraft function! Note that original cannot be invoked on objects that aren't drafts.

import {isDraft, produce} from "immer"

const baseState = {users: [{name: "Bobby"}]}
const nextState = produce(baseState, draft => {
isDraft(draft) // => true
isDraft(draft.users) // => true
isDraft(draft.users[0]) // => true
})
isDraft(nextState) // => false
+ + + + \ No newline at end of file diff --git a/other-lang/index.html b/other-lang/index.html new file mode 100644 index 00000000..cfb6bd0d --- /dev/null +++ b/other-lang/index.html @@ -0,0 +1,26 @@ + + + + + +Porting to other languages | Immer + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/patches/index.html b/patches/index.html new file mode 100644 index 00000000..66ab83a2 --- /dev/null +++ b/patches/index.html @@ -0,0 +1,26 @@ + + + + + +Patches | Immer + + + + + + + + + + + + + + +
+

Patches

egghead.io lesson 14: Capture patches using _produceWithPatches_
egghead.io lesson 16: Apply Patches using _applyPatches_

⚠ Since version 6 support for Patches has to be enabled explicitly by calling enablePatches() once when starting your application.

During the run of a producer, Immer can record all the patches that would replay the changes made by the reducer. This is a very powerful tool if you want to fork your state temporarily and replay the changes to the original.

Patches are useful in few scenarios:

  • To exchange incremental updates with other parties, for example over websockets
  • For debugging / traces, to see precisely how state is changed over time
  • As basis for undo/redo or as an approach to replay changes on a slightly different state tree

To help with replaying patches, applyPatches comes in handy. Here is an example how patches could be used to record the incremental updates and (inverse) apply them:

import {produce, applyPatches} from "immer"

// version 6
import {enablePatches} from "immer"
enablePatches()

let state = {
name: "Micheal",
age: 32
}

// Let's assume the user is in a wizard, and we don't know whether
// his changes should end up in the base state ultimately or not...
let fork = state
// all the changes the user made in the wizard
let changes = []
// the inverse of all the changes made in the wizard
let inverseChanges = []

fork = produce(
fork,
draft => {
draft.age = 33
},
// The third argument to produce is a callback to which the patches will be fed
(patches, inversePatches) => {
changes.push(...patches)
inverseChanges.push(...inversePatches)
}
)

// In the meantime, our original state is replaced, as, for example,
// some changes were received from the server
state = produce(state, draft => {
draft.name = "Michel"
})

// When the wizard finishes (successfully) we can replay the changes that were in the fork onto the *new* state!
state = applyPatches(state, changes)

// state now contains the changes from both code paths!
expect(state).toEqual({
name: "Michel", // changed by the server
age: 33 // changed by the wizard
})

// Finally, even after finishing the wizard, the user might change his mind and undo his changes...
state = applyPatches(state, inverseChanges)
expect(state).toEqual({
name: "Michel", // Not reverted
age: 32 // Reverted
})

The generated patches are similar (but not the same) to the RFC-6902 JSON patch standard, except that the path property is an array, rather than a string. This makes processing patches easier. If you want to normalize to the official specification, patch.path = patch.path.join("/") should do the trick. Anyway, this is what a bunch of patches and their inverse could look like:

[
{
"op": "replace",
"path": ["profile"],
"value": {"name": "Veria", "age": 5}
},
{"op": "remove", "path": ["tags", 3]}
]
[
{"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},
{"op": "add", "path": ["tags", 3], "value": "kiddo"}
]

⚠ Note: The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible. It depends often on the use case what is considered 'optimal', and generating the optimal set of patches is potentially computationally very expensive. So in cases you might want to post process the generated patches, or compress them as explained below.

produceWithPatches

egghead.io lesson 19: Using inverse patches to build undo functionality
egghead.io lesson 20: Use patches to build redo functionality

Instead of setting up a patch listener, an easier way to obtain the patches is to use produceWithPatches, which has the same signature as produce, except that it doesn't return just the next state, but a tuple consisting of [nextState, patches, inversePatches]. Like produce, produceWithPatches supports currying as well.

import {produceWithPatches} from "immer"

const [nextState, patches, inversePatches] = produceWithPatches(
{
age: 33
},
draft => {
draft.age++
}
)

Which produces:

[
{
age: 34
},
[
{
op: "replace",
path: ["age"],
value: 34
}
],
[
{
op: "replace",
path: ["age"],
value: 33
}
]
]

For a more in-depth study, see Distributing patches and rebasing actions using Immer

Tip: Check this trick to compress patches produced over time.

+ + + + \ No newline at end of file diff --git a/performance/index.html b/performance/index.html new file mode 100644 index 00000000..d1d3f061 --- /dev/null +++ b/performance/index.html @@ -0,0 +1,26 @@ + + + + + +Immer performance | Immer + + + + + + + + + + + + + + +
+

Immer performance

egghead.io lesson 5: Leveraging Immer's structural sharing in React
egghead.io lesson 7: Immer will try to re-cycle data if there was no semantic change

Here is a simple benchmark on the performance of Immer. This test takes 50,000 todo items and updates 5,000 of them. Freeze indicates that the state tree has been frozen after producing it. This is a development best practice, as it prevents developers from accidentally modifying the state tree.

Something that isn't reflected in the numbers above, but in reality, Immer is sometimes significantly faster than a hand written reducer. The reason for that is that Immer will detect "no-op" state changes, and return the original state if nothing actually changed, which can avoid a lot of re-renderings for example. Cases are known where simply applying immer solved critical performance issues.

These tests were executed on Node 10.16.3. Use yarn test:perf to reproduce them locally.

performance.png

Most important observation:

  • Immer with proxies is roughly speaking twice to three times slower as a handwritten reducer (the above test case is worst case, see yarn test:perf for more tests). This is in practice negligible.
  • Immer is roughly as fast as ImmutableJS. However, the immutableJS + toJS makes clear the cost that often needs to be paid later; converting the immutableJS objects back to plain objects, to be able to pass them to components, over the network etc... (And there is also the upfront cost of converting data received from e.g. the server to immutable JS)
  • Generating patches doesn't significantly slow down immer
  • The ES5 fallback implementation is roughly twice as slow as the proxy implementation, in some cases worse.

Performance tips

Pre-freeze data

When adding a large data set to the state tree in an Immer producer (for example data received from a JSON endpoint), it is worth to call freeze(json) on the root of the data that is being added first. To shallowly freeze it. This will allow Immer to add the new data to the tree faster, as it will avoid the need to recursively scan and freeze the new data.

You can always opt-out

Realize that immer is opt-in everywhere, so it is perfectly fine to manually write super performance critical reducers, and use immer for all the normal ones. Even from within a producer you opt-out from Immer for certain parts of your logic by using utilies original or current and perform some of your operations on plain JavaScript objects.

For expensive search operations, read from the original state, not the draft

Immer will convert anything you read in a draft recursively into a draft as well. If you have expensive side effect free operations on a draft that involves a lot of reading, for example finding an index using find(Index) in a very large array, you can speed this up by first doing the search, and only call the produce function once you know the index. Thereby preventing Immer to turn everything that was searched for in a draft. Or, alternatively, perform the search on the original value of a draft, by using original(someDraft), which boils to the same thing.

Pull produce as far up as possible

Always try to pull produce 'up', for example for (let x of y) produce(base, d => d.push(x)) is exponentially slower than produce(base, d => { for (let x of y) d.push(x)})

+ + + + \ No newline at end of file diff --git a/pitfalls/index.html b/pitfalls/index.html new file mode 100644 index 00000000..e35b6425 --- /dev/null +++ b/pitfalls/index.html @@ -0,0 +1,26 @@ + + + + + +Pitfalls | Immer + + + + + + + + + + + + + + +
+

Pitfalls

Performance tips

For performance tips, see Performance Tips.

Don't reassign the recipe argument

Never reassign the draft argument (example: draft = myCoolNewState). Instead, either modify the draft or return a new state. See Returning data from producers.

Immer only supports unidirectional trees

Immer assumes your state to be a unidirectional tree. That is, no object should appear twice in the tree, there should be no circular references. There should be exactly one path from the root to any node of the tree.

Never explicitly return undefined from a producer

It is possible to return values from producers, except, it is not possible to return undefined that way, as it is indistinguishable from not updating the draft at all! If you want to replace the draft with undefined, just return nothing from the producer.

Don't mutate exotic objects

Immer does not support exotic objects such as window.location.

Classes should be made draftable or not mutated

You will need to enable your own classes to work properly with Immer. For docs on the topic, check out the section on working with complex objects.

Only valid indices and length can be mutated on Arrays

For arrays, only numeric properties and the length property can be mutated. Custom properties are not preserved on arrays.

Data not originating from the state will never be drafted

Note that data that comes from the closure, and not from the base state, will never be drafted, even when the data has become part of the new draft.

function onReceiveTodo(todo) {
const nextTodos = produce(todos, draft => {
draft.todos[todo.id] = todo
// Note, because 'todo' is coming from external, and not from the 'draft',
// it isn't draft so the following modification affects the original todo!
draft.todos[todo.id].done = true

// The reason for this, is that it means that the behavior of the 2 lines above
// is equivalent to code, making this whole process more consistent
todo.done = true
draft.todos[todo.id] = todo
})
}

Immer patches are not necessarily optimal

The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible.

Always use the result of nested producers

Nested produce calls are supported, but note that produce will always produce a new state. So even when passing a draft to a nested produce, the changes made by the inner produce won't be visible in the draft of the outer produce; those changes will only be visible in the output that the inner produce returns. In other words, when using nested produce, you get a draft of a draft and the result of the inner produce should be merged back into the original draft (or returned). For example produce(state, draft => { produce(draft.user, userDraft => { userDraft.name += "!" })}) won't work as the output of the inner produce isn't used. The correct way to use nested producers is:

produce(state, draft => {
draft.user = produce(draft.user, userDraft => {
userDraft.name += "!"
})
})

Drafts aren't referentially equal

Draft objects in Immer are wrapped in Proxy, so you cannot use == or === to test equality between an original object and its equivalent draft (eg. when matching a specific element in an array). Instead, you can use the original helper:

const remove = produce((list, element) => {
const index = list.indexOf(element) // this won't work!
const index = original(list).indexOf(element) // do this instead
if (index > -1) list.splice(index, 1)
})

const values = [a, b, c]
remove(values, a)

If possible, it's recommended to perform the comparison outside the produce function, or to use a unique identifier property like .id instead, to avoid needing to use original.

+ + + + \ No newline at end of file diff --git a/produce/index.html b/produce/index.html new file mode 100644 index 00000000..58df1375 --- /dev/null +++ b/produce/index.html @@ -0,0 +1,26 @@ + + + + + +Using produce | Immer + + + + + + + + + + + + + + +
+

Using produce

egghead.io lesson 3: Simplifying deep updates with _produce_

The Immer package exposes a produce function that does all the work.

produce(baseState, recipe: (draftState) => void): nextState

produce takes a base state, and a recipe that can be used to perform all the desired mutations on the draft that is passed in. The interesting thing about Immer is that the baseState will be untouched, but the nextState will reflect all changes made to draftState.

Inside the recipe, all standard JavaScript APIs can be used on the draft object, including field assignments, delete operations, and mutating array, Map and Set operations like push, pop, splice, set, sort, remove, etc.

Any of those mutations don't have to happen at the root, but it is allowed to modify anything anywhere deep inside the draft: draft.todos[0].tags["urgent"].author.age = 56

Note that the recipe function itself normally doesn't return anything. However, it is possible to return in case you want to replace the draft object in its entirety with another object, for more details see returning new data.

Example

import {produce} from "immer"

const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]

const nextState = produce(baseState, draftState => {
draftState.push({title: "Tweet about it"})
draftState[1].done = true
})
// the new item is only added to the next state,
// base state is unmodified
expect(baseState.length).toBe(2)
expect(nextState.length).toBe(3)

// same for the changed 'done' prop
expect(baseState[1].done).toBe(false)
expect(nextState[1].done).toBe(true)

// unchanged data is structurally shared
expect(nextState[0]).toBe(baseState[0])
// ...but changed data isn't.
expect(nextState[1]).not.toBe(baseState[1])

Terminology

  • (base)state, the immutable state passed to produce
  • recipe: the second argument of produce, that captures how the base state should be "mutated".
  • draft: the first argument of any recipe, which is a proxy to the original base state that can be safely mutated.
  • producer. A function that uses produce and is generally of the form (baseState, ...arguments) => resultState

Note that it isn't strictly necessary to name the first argument of the recipe draft. You can name it anything you want, for example users. Using draft as a name is just a convention to signal: "mutation is OK here".

+ + + + \ No newline at end of file diff --git a/resources/index.html b/resources/index.html new file mode 100644 index 00000000..b361e771 --- /dev/null +++ b/resources/index.html @@ -0,0 +1,26 @@ + + + + + +External resources | Immer + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/return/index.html b/return/index.html new file mode 100644 index 00000000..f53f6c84 --- /dev/null +++ b/return/index.html @@ -0,0 +1,26 @@ + + + + + +Returning new data from producers | Immer + + + + + + + + + + + + + + +
+

Returning new data from producers

egghead.io lesson 9: Returning completely new state

It is not needed to return anything from a producer, as Immer will return the (finalized) version of the draft anyway. However, it is allowed to just return draft.

It is also allowed to return arbitrarily other data from the producer function. But only if you didn't modify the draft. This can be useful to produce an entirely new state. Some examples:

const userReducer = produce((draft, action) => {
switch (action.type) {
case "renameUser":
// OK: we modify the current state
draft.users[action.payload.id].name = action.payload.name
return draft // same as just 'return'
case "loadUsers":
// OK: we return an entirely new state
return action.payload
case "adduser-1":
// NOT OK: This doesn't do change the draft nor return a new state!
// It doesn't modify the draft (it just redeclares it)
// In fact, this just doesn't do anything at all
draft = {users: [...draft.users, action.payload]}
return
case "adduser-2":
// NOT OK: modifying draft *and* returning a new state
draft.userCount += 1
return {users: [...draft.users, action.payload]}
case "adduser-3":
// OK: returning a new state. But, unnecessary complex and expensive
return {
userCount: draft.userCount + 1,
users: [...draft.users, action.payload]
}
case "adduser-4":
// OK: the immer way
draft.userCount += 1
draft.users.push(action.payload)
return
}
})

Note: It is not possible to return undefined this way, as it is indistinguishable from not updating the draft! Read on...

Producing undefined using nothing

So, in general, one can replace the current state by just returning a new value from the producer, rather than modifying the draft. There is a subtle edge case however: if you try to write a producer that wants to replace the current state with undefined:

produce({}, draft => {
// don't do anything
})

Versus:

produce({}, draft => {
// Try to return undefined from the producer
return undefined
})

The problem is that in JavaScript a function that doesn't return anything also returns undefined! So immer cannot differentiate between those different cases. So, by default, Immer will assume that any producer that returns undefined just tried to modify the draft.

However, to make it clear to Immer that you intentionally want to produce the value undefined, you can return the built-in token nothing:

import {produce, nothing} from "immer"

const state = {
hello: "world"
}

produce(state, draft => {})
produce(state, draft => undefined)
// Both return the original state: { hello: "world"}

produce(state, draft => nothing)
// Produces a new state, 'undefined'

N.B. Note that this problem is specific for the undefined value, any other value, including null, doesn't suffer from this issue.

Tip: to be able to return nothing from a recipe when using TypeScript, the state's type must accept undefined as value.

Inline shortcuts using void

egghead.io lesson 10: Avoid accidental returns by using _void_

Draft mutations in Immer usually warrant a code block, since a return denotes an overwrite. Sometimes that can stretch code a little more than you might be comfortable with.

In such cases, you can use javascripts void operator, which evaluates expressions and returns undefined.

// Single mutation
produce(draft => void (draft.user.age += 1))

// Multiple mutations
produce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))

Code style is highly personal, but for code bases that are to be understood by many, we recommend to stick to the classic draft => { draft.user.age += 1} to avoid cognitive overhead.

+ + + + \ No newline at end of file diff --git a/support/index.html b/support/index.html new file mode 100644 index 00000000..8cbbce74 --- /dev/null +++ b/support/index.html @@ -0,0 +1,26 @@ + + + + + +Supporting immer | Immer + + + + + + + + + + + + + + +
+

Supporting immer

Immer currently has 350.000 dependents on GitHub, and has almost 10.000.000 downloads per month. However, only the first 2 days of development has been sponsored (by Mendix), and all the development and maintenance after that has been a labor of love.

If you are enjoying Immer, and you are grateful for the package, or want to ensure its longevity, consider sponsoring the open collective on https://opencollective.com/immer or make a one time donation using PayPal.

+ + + + \ No newline at end of file diff --git a/typescript/index.html b/typescript/index.html new file mode 100644 index 00000000..2b310f73 --- /dev/null +++ b/typescript/index.html @@ -0,0 +1,26 @@ + + + + + +Using TypeScript or Flow | Immer + + + + + + + + + + + + + + +
+

Using TypeScript or Flow

egghead.io lesson 12: Immer + TypeScript

The Immer package ships with type definitions inside the package, which should be picked up by TypeScript and Flow out of the box and without further configuration.

The TypeScript typings automatically remove readonly modifiers from your draft types and return a value that matches your original type. See this practical example:

import {produce} from "immer"

interface State {
readonly x: number
}

// `x` cannot be modified here
const state: State = {
x: 0
}

const newState = produce(state, draft => {
// `x` can be modified here
draft.x++
})

// `newState.x` cannot be modified here

This ensures that the only place you can modify your state is in your produce callbacks. It even works recursively and with ReadonlyArray.

Best practices

  1. Always define your states as readonly as much as possible. This best reflects the mental model and reality, since Immer will freeze all its returned values.
  2. You can use the utility type Immutable to recursively make an entire type tree read-only, e.g.: type ReadonlyState = Immutable<State>.
  3. Immer won't automatically wrap all returned types in Immutable if the original type of the input state wasn't immutable. This is to make sure it doesn't break code bases that don't use immutable types.

Tips for curried producers

We try to inference as much as possible. So if a curried producer is created and directly passed to another function, we can infer the type from there. This works well with for example React:

import {Immutable, produce} from "immer"

type Todo = Immutable<{
title: string
done: boolean
}>

// later...

const [todo, setTodo] = useState<Todo>({
title: "test",
done: true
})

// later...

setTodo(
produce(draft => {
// draft will be strongly typed and mutable!
draft.done = !draft.done
})
)

When a curried producer isn't passed directly somewhere else, Immer can infer the state type from the draft argument. For example when doing the following:

// See below for a better solution!

const toggler = produce((draft: Draft<Todo>) => {
draft.done = !draft.done
})

// typeof toggler = (state: Immutable<Todo>) => Writable<Todo>

Note that we did wrap the Todo type of the draft argument with Draft, because Todo is a readonly type. For non-readonly types this isn't needed.

For the returned curried function, toggler, We will narrow the input type to Immutable<Todo>, so that even though Todo is a mutable type, we will still accept an immutable todo as input argument to toggler.

In contrast, Immer will widen the output type of the curried function to Writable<Todo>, to make sure it's output state is also assignable to variables that are not explictly typed to be immutable.

This type narrowing / widening behavior might be unwelcome, maybe even for the simple reason that it results in quite noisy types. So we recommend to specify the generic state type for curried producers instead, in cases where it cannot be inferred directly, like toggler above. By doing so the automatic output widening / input narrowing will be skipped. However, the draft argument itself will still be inferred to be a writable Draft<Todo>:

const toggler = produce<Todo>(draft => {
draft.done = !draft.done
})

// typeof toggler = (state: Todo) => Todo

However, in case the curried producer is defined with an initial state, Immer can infer the state type from the initial state, so in that case the generic doesn't need to be specified either:

const state0: Todo = {
title: "test",
done: false
}

// No type annotations needed, since we can infer from state0.
const toggler = produce(draft => {
draft.done = !draft.done
}, state0)

// typeof toggler = (state: Todo) => Todo

In case the toggler has no initial state, and it has curried arguments, and you set the state generic explicitly, then type of any additional arguments should be defined explicitly as a tuple type as well:

const toggler = produce<Todo, [boolean]>((draft, newState) => {
draft.done = newState
})

// typeof toggler = (state: Todo, newState: boolean) => Todo

Cast utilities

The types inside and outside a produce can be conceptually the same, but from a practical perspective different. For example, the State in the examples above should be considered immutable outside produce, but mutable inside produce.

Sometimes this leads to practical conflicts. Take the following example:

type Todo = {readonly done: boolean}

type State = {
readonly finishedTodos: readonly Todo[]
readonly unfinishedTodos: readonly Todo[]
}

function markAllFinished(state: State) {
produce(state, draft => {
draft.finishedTodos = state.unfinishedTodos
})
}

This will generate the error:

The type 'readonly Todo[]' is 'readonly' and cannot be assigned to the mutable type '{ done: boolean; }[]'

The reason for this error is that we assign our read only, immutable array to our draft, which expects a mutable type, with methods like .push etc etc. As far as TS is concerned, those are not exposed from our original State. To hint TypeScript that we want to upcast the collection here to a mutable array for draft purposes, we can use the utility castDraft:

draft.finishedTodos = castDraft(state.unfinishedTodos) will make the error disappear.

There is also the utility castImmutable, in case you ever need to achieve the opposite. Note that these utilities are for all practical purposes no-ops, they will just return their original value.

Tip: You can combine castImmutable with produce to type the return type of produce as something immutable, even when the original state was mutable:

// a mutable data structure
const baseState = {
todos: [{
done: false
}]
}

const nextState = castImmutable(produce(baseState, _draft => {}))

// inferred type of nextState is now:
{
readonly todos: ReadonlyArray<{
readonly done: boolean
}>
})

Compatibility

Note: Immer v5.3+ supports TypeScript v3.7+ only.

Note: Immer v3.0+ supports TypeScript v3.4+ only.

Note: Immer v1.9+ supports TypeScript v3.1+ only.

Note: Flow support might be removed in future versions and we recommend TypeScript

+ + + + \ No newline at end of file diff --git a/update-patterns/index.html b/update-patterns/index.html new file mode 100644 index 00000000..9513b5e0 --- /dev/null +++ b/update-patterns/index.html @@ -0,0 +1,26 @@ + + + + + +Update patterns | Immer + + + + + + + + + + + + + + +
+

Update patterns

Working with immutable data, before Immer, used to mean learning all the immutable update patterns.

To help 'unlearning' those patterns here is an overview how you can leverage the built-in JavaScript APIs to update objects and collections:

Object mutations

import {produce} from "immer"

const todosObj = {
id1: {done: false, body: "Take out the trash"},
id2: {done: false, body: "Check Email"}
}

// add
const addedTodosObj = produce(todosObj, draft => {
draft["id3"] = {done: false, body: "Buy bananas"}
})

// delete
const deletedTodosObj = produce(todosObj, draft => {
delete draft["id1"]
})

// update
const updatedTodosObj = produce(todosObj, draft => {
draft["id1"].done = true
})

Array mutations

import {produce} from "immer"

const todosArray = [
{id: "id1", done: false, body: "Take out the trash"},
{id: "id2", done: false, body: "Check Email"}
]

// add
const addedTodosArray = produce(todosArray, draft => {
draft.push({id: "id3", done: false, body: "Buy bananas"})
})

// delete by index
const deletedTodosArray = produce(todosArray, draft => {
draft.splice(3 /*the index */, 1)
})

// update by index
const updatedTodosArray = produce(todosArray, draft => {
draft[3].done = true
})

// insert at index
const updatedTodosArray = produce(todosArray, draft => {
draft.splice(3, 0, {id: "id3", done: false, body: "Buy bananas"})
})

// remove last item
const updatedTodosArray = produce(todosArray, draft => {
draft.pop()
})

// remove first item
const updatedTodosArray = produce(todosArray, draft => {
draft.shift()
})

// add item at the beginning of the array
const addedTodosArray = produce(todosArray, draft => {
draft.unshift({id: "id3", done: false, body: "Buy bananas"})
})

// delete by id
const deletedTodosArray = produce(todosArray, draft => {
const index = draft.findIndex(todo => todo.id === "id1")
if (index !== -1) draft.splice(index, 1)
})

// update by id
const updatedTodosArray = produce(todosArray, draft => {
const index = draft.findIndex(todo => todo.id === "id1")
if (index !== -1) draft[index].done = true
})

// filtering items
const updatedTodosArray = produce(todosArray, draft => {
// creating a new state is simpler in this example
// (note that we don't need produce in this case,
// but as shown below, if the filter is not on the top
// level produce is still pretty useful)
return draft.filter(todo => todo.done)
})

Nested data structures

import {produce} from "immer"

// example complex data structure
const store = {
users: new Map([
[
"17",
{
name: "Michel",
todos: [
{
title: "Get coffee",
done: false
}
]
}
]
])
}

// updating something deeply in-an-object-in-an-array-in-a-map-in-an-object:
const nextStore = produce(store, draft => {
draft.users.get("17").todos[0].done = true
})

// filtering out all unfinished todo's
const nextStore = produce(store, draft => {
const user = draft.users.get("17")
// when filtering, creating a fresh collection is simpler than
// removing irrelevant items
user.todos = user.todos.filter(todo => todo.done)
})

Note that many array operations can be used to insert multiple items at once by passing multiple arguments or using the spread operation: todos.unshift(...items).

Note that when working with arrays that contain objects that are typically identified by some id, we recommend to use Map or index based objects (as shown above) instead of performing frequent find operations, lookup tables perform much better in general.

+ + + + \ No newline at end of file diff --git a/zh-CN/.nojekyll b/zh-CN/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/zh-CN/404.html b/zh-CN/404.html new file mode 100644 index 00000000..2babd6c7 --- /dev/null +++ b/zh-CN/404.html @@ -0,0 +1,26 @@ + + + + + +找不到页面 | Immer + + + + + + + + + + + + + + +
+

找不到页面

我们找不到您要找的页面。

请联系原始链接来源网站的所有者,并告知他们链接已损坏。

+ + + + \ No newline at end of file diff --git a/zh-CN/api/index.html b/zh-CN/api/index.html new file mode 100644 index 00000000..92be2d28 --- /dev/null +++ b/zh-CN/api/index.html @@ -0,0 +1,26 @@ + + + + + +API 概览 | Immer + + + + + + + + + + + + + + +
+

API 概览

导出名称描述章节
(default)Immer 核心 API,通常命名为 produce: import {produce} from "immer"Produce
applyPatches给定一个基本 state 或 draft,以及一组 patches ,应用 patchesPatches
castDraft将任何不可变类型转换为其可变对应物。这只是一个转换,实际上并没有做任何事情。TypeScript
castImmutable将任何可变类型转换为其不可变对应物。这只是一个转换,实际上并没有做任何事情。TypeScript
createDraft给定一个基本 state,创建一个可变 draft,任何修改都将被记录下来Async
current给定一个 draft 对象(不必是对象的根结点),对 draft 的当前状态进行快照Current
Draft<T>暴露的 TypeScript 类型以将不可变类型转换为可变类型TypeScript
enableMapSet()启用对 MapSet 集合的支持。Installation
enablePatches()启用对 JSON patches 的支持Installation
finishDraft给定使用 createDraft 创建的 draft,冻结 draft 并生成并返回下一个不可变状态,该状态捕获所有更改Async
freeze(obj, deep?)冻结可 draft 对象。返回原始对象。默认情况下浅冻结,但如果第二个参数为真,它将递归冻结。
Immer可用于创建第二个“immer”实例(暴露此实例中列出的所有 API)的构造函数,它不与全局实例共享其设置
immerable可以添加到构造函数或原型的符号,表示 Immer 应该将类视为可以安全 draft 的东西Classes
Immutable<T>暴露的 TypeScript 类型以将可变类型转换为不可变类型
isDraft如果给定对象是 draft 对象,则返回 true
isDraftable如果 Immer 能够将此对象变成 draft,则返回 true。这适用于:数组、没有原型的对象、以 Object 为原型的对象、在其构造函数或原型上具有 immerable 符号的对象
nothing可以从 recipe 返回的值,以指示应生成 undefinedReturn
original给定一个 draft 对象(不必是对象的根结点),返回原始状态树中相同路径的原始对象(如果存在)Original
Patch暴露的 TypeScript 类型,描述(反向)patches 对象的形状Patches
produceImmer 的核心 API,也暴露为 default 导出Produce
produceWithPatchesproduce 相同,但它不仅返回生成的对象,还返回一个由 [result, patch, inversePatches] 组成的元组Patches
setAutoFreeze启用/禁用递归的自动冻结。默认启用Freezing
setUseStrictShallowCopy可用于启用严格的浅拷贝。 如果启用,immer 会尽可能多地拷贝不可枚举属性Classes

导入 immer

produce 作为默认导出,但也可以选择将其用作名称导入,因为这有利于一些较旧的项目设置。所以下面的导入都是正确的,这里推荐第一个:

import {produce} from "immer"
import {produce} from "immer"

const {produce} = require("immer")
const produce = require("immer").produce
const produce = require("immer").default

import unleashTheMagic from "immer"
import {produce as unleashTheMagic} from "immer"
+ + + + \ No newline at end of file diff --git a/zh-CN/assets/css/styles.d8d8e956.css b/zh-CN/assets/css/styles.d8d8e956.css new file mode 100644 index 00000000..f859c0e0 --- /dev/null +++ b/zh-CN/assets/css/styles.d8d8e956.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:transparent;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:rgba(0,0,0,.05);--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 rgba(0,0,0,.1);--ifm-global-shadow-md:0 5px 40px rgba(0,0,0,.2);--ifm-global-shadow-tl:0 12px 28px 0 rgba(0,0,0,.2),0 2px 4px 0 rgba(0,0,0,.1);--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:transparent;--ifm-table-stripe-background:rgba(0,0,0,.03);--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:transparent}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid rgba(0,0,0,.1);border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:transparent;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c200c2}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:rgba(53,120,229,.15);--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:rgba(235,237,240,.15);--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:rgba(0,164,0,.15);--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:rgba(84,199,236,.15);--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:rgba(255,186,0,.15);--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:rgba(250,56,62,.15);--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{-moz-column-gap:var(--ifm-avatar-intro-margin);column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs__link:-moz-any-link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs__link:any-link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:transparent;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.content_knG7 a,a:hover{text-decoration:underline}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor transparent;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:hsla(0,0%,100%,.1);--ifm-navbar-search-input-placeholder-color:hsla(0,0%,100%,.5);color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:hsla(0,0%,100%,.05);--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::-moz-placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:rgba(0,0,0,.6);right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{-moz-column-gap:var(--ifm-pagination-page-spacing);column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.tocCollapsibleContent_vkbj a,details a{display:block}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid transparent;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:hsla(0,0%,100%,.05);--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:hsla(0,0%,100%,.1);--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:hsla(0,0%,100%,.07);--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}:root{--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-link-color:#c200c2;--docusaurus-announcement-bar-height:auto!important;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:transparent;--docusaurus-collapse-button-bg-hover:rgba(0,0,0,.1);--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}.navbar--dark{--ifm-navbar-background-color:#000;--ifm-menu-color:#fff;--ifm-menu-color-background-hover:hsla(0,0%,100%,.1)}.navbar--fixed-top{color:#fff;font-weight:700}.navbar--fixed-top a{color:#fff}details{background:#e2e2e2;margin-bottom:20px}details[open]{border-bottom:2px solid #c200c2}details iframe{padding:0 20px}details a{color:#666;font-size:.8em;text-align:right}.egghead-summary{background:#c200c2;border-radius:2px;color:#fff;cursor:pointer;margin:0;padding:5px}.egghead-link{font-style:italic;margin:5px;padding:5px}iframe{border:none}.dropdown__link{color:#000!important}div[class^=announcementBarContent]{font-size:20px;font-weight:700;line-height:40px;padding:8px 30px}div[class^=announcementBarContent] a{color:var(--ifm-color-primary-lightest)!important;display:inline-block;text-decoration:underline}div[class^=announcementBarContent] a:hover{color:var(--brand)!important}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;-moz-user-select:none;user-select:none}.hash-link:before{content:"#"}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{-moz-column-gap:.2rem;column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:transparent transparent transparent var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:hsla(0,0%,100%,.05);--docusaurus-collapse-button-bg-hover:hsla(0,0%,100%,.1)}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_b6E3,.sidebarLogo_isFc{display:none}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media only screen and (max-width:768px){.announcement{font-size:18px}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media only screen and (max-width:500px){.announcement{font-size:15px;line-height:22px;padding:6px 30px}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/zh-CN/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png b/zh-CN/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png new file mode 100644 index 00000000..c83185f8 Binary files /dev/null and b/zh-CN/assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png differ diff --git a/zh-CN/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png b/zh-CN/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png new file mode 100644 index 00000000..1fd5c8be Binary files /dev/null and b/zh-CN/assets/images/performance-c7f59d06ec36f4a05b6403daada96542.png differ diff --git a/zh-CN/assets/js/04a45149.d006067c.js b/zh-CN/assets/js/04a45149.d006067c.js new file mode 100644 index 00000000..c7ced94b --- /dev/null +++ b/zh-CN/assets/js/04a45149.d006067c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[844],{3905:(e,t,a)=>{a.d(t,{Zo:()=>l,kt:()=>d});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),o=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},l=function(e){var t=o(e.components);return n.createElement(c.Provider,{value:t},e.children)},h="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),h=o(a),u=r,d=h["".concat(c,".").concat(u)]||h[u]||m[u]||s;return a?n.createElement(d,i(i({ref:t},l),{},{components:a})):n.createElement(d,i({ref:t},l))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=a.length,i=new Array(s);i[0]=u;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[h]="string"==typeof e?e:r,i[1]=p;for(var o=2;o{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>u,frontMatter:()=>p,metadata:()=>o,toc:()=>h});var n=a(3117),r=a(102),s=(a(7294),a(3905)),i=["components"],p={id:"patches",title:"Patches"},c=void 0,o={unversionedId:"patches",id:"patches",title:"Patches",description:"produceWithPatches",id:"producewithpatches",level:3}],m={toc:h};function u(e){var t=e.components,a=(0,r.Z)(e,i);return(0,s.kt)("wrapper",(0,n.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("center",null,(0,s.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",className:"horizontal bordered"}))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io \u7b2c14\u8bfe: \u4f7f\u7528 produceWithPatches \u6355\u83b7 Patches"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches"},"Hosted on egghead.io"))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io \u7b2c16\u8bfe: \u4f7f\u7528 applyPatches \u5e94\u7528 Patches"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients"},"Hosted on egghead.io")),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"\u26a0 \u5728\u7248\u672c 6 \u4e4b\u540e\uff0c\u5fc5\u987b\u5728\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u8c03\u7528\u4e00\u6b21 ",(0,s.kt)("a",{parentName:"em",href:"/immer/zh-CN/installation#pick-your-immer-version"},(0,s.kt)("inlineCode",{parentName:"a"},"enablePatches()"))," \u6765\u542f\u7528\u5bf9 Patches \u7684\u652f\u6301\u3002")),(0,s.kt)("p",null,"\u5728 producer \u8fd0\u884c\u671f\u95f4\uff0cImmer \u53ef\u4ee5\u8bb0\u5f55\u6240\u6709\u7684\u8865\u4e01\u6765\u56de\u6eaf reducer \u9020\u6210\u7684\u66f4\u6539 \u3002\u8fd9\u662f\u4e00\u4e2a\u975e\u5e38\u5f3a\u5927\u7684\u5de5\u5177\uff0c\u5982\u679c\u60a8\u60f3\u6682\u65f6 fork \u60a8\u7684\u72b6\u6001\u5e76\u56de\u6eaf\u5bf9\u539f\u59cb\u72b6\u6001\u7684\u66f4\u6539\u3002"),(0,s.kt)("p",null,"Patches \u5728\u4e0b\u9762\u573a\u666f\u5f88\u6709\u7528:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"\u4e0e\u5176\u4ed6\u65b9\u4ea4\u6362\u589e\u91cf\u66f4\u65b0\uff0c\u4f8b\u5982\u901a\u8fc7"),(0,s.kt)("li",{parentName:"ul"},"\u5bf9\u4e8e\u8c03\u8bd5/\u8ddf\u8e2a\uff0c\u51c6\u786e\u67e5\u770b\u72b6\u6001\u5982\u4f55\u968f\u65f6\u95f4\u53d8\u5316"),(0,s.kt)("li",{parentName:"ul"},"\u4f5c\u4e3a\u64a4\u6d88/\u91cd\u505a\u7684\u57fa\u7840\u6216\u4f5c\u4e3a\u5728\u7a0d\u5fae\u4e0d\u540c\u7684\u72b6\u6001\u6811\u4e0a\u56de\u6eaf\u66f4\u6539\u7684\u65b9\u6cd5\u3002")),(0,s.kt)("p",null,"\u4e3a\u4e86\u5e2e\u52a9\u56de\u6eaf\u8865\u4e01\uff0c",(0,s.kt)("inlineCode",{parentName:"p"},"applyPatches")," \u6d3e\u4e0a\u7528\u573a\u4e86\u3002\u8fd9\u662f\u4e00\u4e2a\u5982\u4f55\u4f7f\u7528 Patches \u6765\u8bb0\u5f55\u589e\u91cf\u66f4\u65b0\u5e76\uff08\u53cd\u5411\uff09\u5e94\u7528\u5b83\u4eec\u7684\u793a\u4f8b\uff1a"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce, applyPatches} from "immer"\n\n// \u7248\u672c 6\nimport {enablePatches} from "immer"\nenablePatches()\n\nlet state = {\n name: "Micheal",\n age: 32\n}\n\n// \u5047\u8bbe\u7528\u6237\u5728\u5411\u5bfc\u4e2d\n// \u4ed6\u7684\u66f4\u6539 \u5e94\u8be5\u4ee5\u6700\u7ec8\u662f\u5426\u4e3a\u57fa\u672c\u72b6\u6001\u7ed3\u675f...\n\nlet fork = state\n// \u7528\u6237\u5728\u5411\u5bfc\u4e2d\u6240\u4f5c\u7684\u6240\u6709\u66f4\u6539\nlet changes = []\n// \u4e0e\u5411\u5bfc\u4e2d\u6240\u505a\u7684\u6240\u6709\u66f4\u6539\u76f8\u53cd\nlet inverseChanges = []\n\nfork = produce(\n fork,\n draft => {\n draft.age = 33\n },\n // \u4ea7\u751f\u7684\u7b2c\u4e09\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u56de\u8c03\uff0cpatches \u5c06\u4ece\u8fd9\u91cc\u4ea7\u751f\n (patches, inversePatches) => {\n changes.push(...patches)\n inverseChanges.push(...inversePatches)\n }\n)\n\n// \u540c\u65f6\uff0c\u6211\u4eec\u7684\u539f\u59cb\u72b6\u6001\u88ab\u66ff\u6362\uff0c\u4f8b\u5982\n// \u4ece\u670d\u52a1\u5668\u6536\u5230\u4e86\u4e00\u4e9b\u66f4\u6539\nstate = produce(state, draft => {\n draft.name = "Michel"\n})\n\n// \u5f53\u5411\u5bfc\u5b8c\u6210\uff08\u6210\u529f\uff09\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06 fork \u4e2d\u7684\u66f4\u6539\u91cd\u64ad\u5230\u65b0\u7684\u72b6\u6001\uff01\nstate = applyPatches(state, changes)\n\n// state \u73b0\u5728\u5305\u542b\u6765\u81ea\u4e24\u4e2a\u4ee3\u7801\u8def\u5f84\u7684\u66f4\u6539\uff01\nexpect(state).toEqual({\n name: "Michel", // \u670d\u52a1\u5668\u66f4\u6539\n age: 33 // \u5411\u5bfc\u66f4\u6539\n})\n\n// \u6700\u540e\uff0c\u5373\u4f7f\u5728\u5b8c\u6210\u5411\u5bfc\u4e4b\u540e\uff0c\u7528\u6237\u4e5f\u53ef\u80fd\u4f1a\u6539\u53d8\u4e3b\u610f\u5e76\u64a4\u6d88\u4ed6\u7684\u66f4\u6539......\nstate = applyPatches(state, inverseChanges)\nexpect(state).toEqual({\n name: "Michel", // \u6ca1\u6709\u8fd8\u539f\n age: 32 // \u8fd8\u539f\u4e86\n})\n')),(0,s.kt)("p",null,"\u751f\u6210\u7684 patches \u4e0e ",(0,s.kt)("a",{parentName:"p",href:"https://datatracker.ietf.org/doc/html/rfc6902/#section-4.1"},"RFC-6902 JSON patch standard")," \u7c7b\u4f3c\uff08\u4f46\u5e76\u4e0d\u76f8\u540c\uff09\uff0c\u9664\u4e86 path \u5c5e\u6027\u662f\u4e00\u4e2a\u6570\u7ec4\uff0c\u800c\u4e0d\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002\u8fd9\u4f7f\u5f97\u5904\u7406 patches \u66f4\u52a0\u5bb9\u6613\u3002\u5982\u679c\u4f60\u60f3\u89c4\u8303\u5316\u5230\u5b98\u65b9\u683c\u5f0f\uff0c",(0,s.kt)("inlineCode",{parentName:"p"},'patch.path = patch.path.join("/")'),"\u5e94\u8be5\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002\u65e0\u8bba\u5982\u4f55\uff0c\u4e0b\u9762\u5c31\u662f\u4e00\u5806 patches \u548c\u5b83\u4eec\u56de\u6eaf\u7684\u6837\u5b50\u3002"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "op": "replace",\n "path": ["profile"],\n "value": {"name": "Veria", "age": 5}\n },\n {"op": "remove", "path": ["tags", 3]}\n]\n')),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'[\n {"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},\n {"op": "add", "path": ["tags", 3], "value": "kiddo"}\n]\n')),(0,s.kt)("p",null,"\u26a0 \u6ce8\u610f: Immer \u751f\u6210\u7684\u8865\u4e01\u96c6\u5e94\u8be5\u662f\u6b63\u786e\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u5c06\u5b83\u4eec\u5e94\u7528\u4e8e\u76f8\u540c\u7684\u57fa\u7840\u5bf9\u8c61\u5e94\u8be5\u4f1a\u5bfc\u81f4\u76f8\u540c\u7684\u6700\u7ec8\u72b6\u6001\u3002\u7136\u800c\uff0cImmer \u4e0d\u4fdd\u8bc1\u751f\u6210\u7684\u8865\u4e01\u96c6\u662f\u6700\u4f18\u7684\uff0c\u5373\u53ef\u80fd\u7684\u6700\u5c0f\u8865\u4e01\u96c6\u3002\u5b83\u901a\u5e38\u53d6\u51b3\u4e8e\u88ab\u8ba4\u4e3a\u662f\u201c\u6700\u4f73\u201d\u7684\u7528\u4f8b\uff0c\u5e76\u4e14\u751f\u6210\u6700\u4f73\u8865\u4e01\u96c6\u5728\u8ba1\u7b97\u4e0a\u53ef\u80fd\u975e\u5e38\u6602\u8d35\u3002\u56e0\u6b64\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u80fd\u60f3\u8981\u5bf9\u751f\u6210\u7684\u8865\u4e01\u8fdb\u884c\u540e\u5904\u7406\uff0c\u6216\u8005\u6309\u7167\u4e0b\u9762\u7684\u8bf4\u660e\u538b\u7f29\u5b83\u4eec\u3002"),(0,s.kt)("h3",{id:"producewithpatches"},(0,s.kt)("inlineCode",{parentName:"h3"},"produceWithPatches")),(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io \u7b2c19\u8bfe: \u4f7f\u7528\u56de\u6eaf patches \u6784\u5efa\u64a4\u9500\u529f\u80fd"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality"},"Hosted on egghead.io"))," ",(0,s.kt)("details",null,(0,s.kt)("summary",{className:"egghead-summary"},"egghead.io \u7b2c20\u8bfe: \u4f7f\u7528 patches \u6784\u5efa\u91cd\u505a\u529f\u80fd"),(0,s.kt)("br",null),(0,s.kt)("div",null,(0,s.kt)("iframe",{width:"760",height:"427",scrolling:"no",src:"https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality/embed"})),(0,s.kt)("a",{className:"egghead-link",href:"https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality"},"Hosted on egghead.io")),(0,s.kt)("p",null,"\u9664\u4e86\u8bbe\u7f6e patch \u76d1\u542c\u5668\u4e4b\u5916\uff0c\u83b7\u53d6 patches \u7684\u66f4\u7b80\u5355\u65b9\u6cd5\u662f\u4f7f\u7528 ",(0,s.kt)("inlineCode",{parentName:"p"},"produceWithPatches"),"\uff0c\u5b83\u4e0e ",(0,s.kt)("inlineCode",{parentName:"p"},"produce")," \u5177\u6709\u76f8\u540c\u7684\u7b7e\u540d\uff0c\u4e0d\u8fc7\u5b83\u4e0d\u6b62\u8fd4\u56de next state\uff0c\u800c\u662f\u4e00\u4e2a\u5305\u542b ",(0,s.kt)("inlineCode",{parentName:"p"},"[nextState, patches, inversePatches]")," \u7684\u5143\u7ec4\uff0c\u548c ",(0,s.kt)("inlineCode",{parentName:"p"},"produce")," \u4e00\u6837\uff0c",(0,s.kt)("inlineCode",{parentName:"p"},"produceWithPatches")," \u4e5f\u652f\u6301\u67ef\u91cc\u5316\u3002"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produceWithPatches} from "immer"\n\nconst [nextState, patches, inversePatches] = produceWithPatches(\n {\n age: 33\n },\n draft => {\n draft.age++\n }\n)\n')),(0,s.kt)("p",null,"\u5c06\u8fd4\u56de:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},';[\n {\n age: 34\n },\n [\n {\n op: "replace",\n path: ["age"],\n value: 34\n }\n ],\n [\n {\n op: "replace",\n path: ["age"],\n value: 33\n }\n ]\n]\n')),(0,s.kt)("p",null,"\u6709\u5173\u66f4\u6df1\u5165\u7684\u7814\u7a76\uff0c\u8bf7\u53c2\u9605\u4f7f\u7528 ",(0,s.kt)("a",{parentName:"p",href:"https://medium.com/@mweststrate/distributing-state-changes-using-snapshots-patches-and-actions-part-2-2f50d8363988"},"Distributing patches and rebasing actions using Immer")),(0,s.kt)("p",null,"\u63d0\u793a\uff1a\u4f7f\u7528\u6b64\u6280\u5de7\u53ef\u4ee5 ",(0,s.kt)("a",{parentName:"p",href:"https://medium.com/@david.b.edelstein/using-immer-to-compress-immer-patches-f382835b6c69"},"compress patches")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/zh-CN/assets/js/17896441.9ee3f929.js b/zh-CN/assets/js/17896441.9ee3f929.js new file mode 100644 index 00000000..0bf6aa2b --- /dev/null +++ b/zh-CN/assets/js/17896441.9ee3f929.js @@ -0,0 +1 @@ +(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[918],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>v});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=s(n),p=r,v=d["".concat(c,".").concat(p)]||d[p]||m[p]||l;return n?a.createElement(v,o(o({ref:t},u),{},{components:n})):a.createElement(v,o({ref:t},u))}));function v(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=p;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[d]="string"==typeof e?e:r,o[1]=i;for(var s=2;s{"use strict";n.r(t),n.d(t,{default:()=>$t});var a=n(7294),r=n(1944),l=n(4700),o=a.createContext(null);function i(e){var t=e.children,n=function(e){return(0,a.useMemo)((function(){return{metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc}}),[e])}(e.content);return a.createElement(o.Provider,{value:n},t)}function c(){var e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocProvider");return e}function s(){var e,t=c(),n=t.metadata,l=t.frontMatter,o=t.assets;return a.createElement(r.d,{title:n.title,description:n.description,keywords:l.keywords,image:null!=(e=o.image)?e:l.image})}var u=n(6010),d=n(7524),m=n(3117),p=n(5999),v=n(9960);function f(e){var t=e.permalink,n=e.title,r=e.subLabel,l=e.isNext;return a.createElement(v.Z,{className:(0,u.Z)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},r&&a.createElement("div",{className:"pagination-nav__sublabel"},r),a.createElement("div",{className:"pagination-nav__label"},n))}function h(e){var t=e.previous,n=e.next;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,p.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&a.createElement(f,(0,m.Z)({},t,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(f,(0,m.Z)({},n,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function g(){var e=c().metadata;return a.createElement(h,{previous:e.previous,next:e.next})}var b=n(2263),E=n(143),y=n(5281),k=n(373),N=n(4477);var L={unreleased:function(e){var t=e.siteTitle,n=e.versionMetadata;return a.createElement(p.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){var t=e.siteTitle,n=e.versionMetadata;return a.createElement(p.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function C(e){var t=L[e.versionMetadata.banner];return a.createElement(t,e)}function Z(e){var t=e.versionLabel,n=e.to,r=e.onClick;return a.createElement(p.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(v.Z,{to:n,onClick:r},a.createElement(p.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){var t,n=e.className,r=e.versionMetadata,l=(0,b.Z)().siteConfig.title,o=(0,E.gA)({failfast:!0}).pluginId,i=(0,k.J)(o).savePreferredVersionName,c=(0,E.Jo)(o),s=c.latestDocSuggestion,d=c.latestVersionSuggestion,m=null!=s?s:(t=d).docs.find((function(e){return e.id===t.mainDocId}));return a.createElement("div",{className:(0,u.Z)(n,y.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(C,{siteTitle:l,versionMetadata:r})),a.createElement("div",{className:"margin-top--md"},a.createElement(Z,{versionLabel:d.label,to:m.path,onClick:function(){return i(d.name)}})))}function _(e){var t=e.className,n=(0,N.E)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function w(e){var t=e.className,n=(0,N.E)();return n.badge?a.createElement("span",{className:(0,u.Z)(t,y.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(p.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function x(e){var t=e.lastUpdatedAt,n=e.formattedLastUpdatedAt;return a.createElement(p.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function B(e){var t=e.lastUpdatedBy;return a.createElement(p.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function O(e){var t=e.lastUpdatedAt,n=e.formattedLastUpdatedAt,r=e.lastUpdatedBy;return a.createElement("span",{className:y.k.common.lastUpdated},a.createElement(p.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(x,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:r?a.createElement(B,{lastUpdatedBy:r}):""}},"Last updated{atDate}{byUser}"),!1)}var j=n(102);const A="iconEdit_Z9Sw";var H=["className"];function M(e){var t=e.className,n=(0,j.Z)(e,H);return a.createElement("svg",(0,m.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.Z)(A,t),"aria-hidden":"true"},n),a.createElement("g",null,a.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function S(e){var t=e.editUrl;return a.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:y.k.common.editThisPage},a.createElement(M,null),a.createElement(p.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const I="tag_zVej",P="tagRegular_sFm0",U="tagWithCount_h2kH";function z(e){var t=e.permalink,n=e.label,r=e.count;return a.createElement(v.Z,{href:t,className:(0,u.Z)(I,r?U:P)},n,r&&a.createElement("span",null,r))}const V="tags_jXut",D="tag_QGVx";function R(e){var t=e.tags;return a.createElement(a.Fragment,null,a.createElement("b",null,a.createElement(p.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),a.createElement("ul",{className:(0,u.Z)(V,"padding--none","margin-left--sm")},t.map((function(e){var t=e.label,n=e.permalink;return a.createElement("li",{key:n,className:D},a.createElement(z,{label:t,permalink:n}))}))))}const W="lastUpdated_vwxv";function F(e){return a.createElement("div",{className:(0,u.Z)(y.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(R,e)))}function q(e){var t=e.editUrl,n=e.lastUpdatedAt,r=e.lastUpdatedBy,l=e.formattedLastUpdatedAt;return a.createElement("div",{className:(0,u.Z)(y.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(S,{editUrl:t})),a.createElement("div",{className:(0,u.Z)("col",W)},(n||r)&&a.createElement(O,{lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:r})))}function G(){var e=c().metadata,t=e.editUrl,n=e.lastUpdatedAt,r=e.formattedLastUpdatedAt,l=e.lastUpdatedBy,o=e.tags,i=o.length>0,s=!!(t||n||l);return i||s?a.createElement("footer",{className:(0,u.Z)(y.k.docs.docFooter,"docusaurus-mt-lg")},i&&a.createElement(F,{tags:o}),s&&a.createElement(q,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:r})):null}var Y=n(6043),$=n(6668),J=["parentIndex"];function Q(e){var t=e.map((function(e){return Object.assign({},e,{parentIndex:-1,children:[]})})),n=Array(7).fill(-1);t.forEach((function(e,t){var a=n.slice(2,e.level);e.parentIndex=Math.max.apply(Math,a),n[e.level]=t}));var a=[];return t.forEach((function(e){var n=e.parentIndex,r=(0,j.Z)(e,J);n>=0?t[n].children.push(r):a.push(r)})),a}function X(e){var t=e.toc,n=e.minHeadingLevel,a=e.maxHeadingLevel;return t.flatMap((function(e){var t=X({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[Object.assign({},e,{children:t})]:t}))}function K(e){var t=e.getBoundingClientRect();return t.top===t.bottom?K(e.parentNode):t}function ee(e,t){var n,a,r=t.anchorTopOffset,l=e.find((function(e){return K(e).top>=r}));return l?function(e){return e.top>0&&e.bottom0})).map((function(e){return[e-1,[i]]}));return{lineClassNames:Object.fromEntries(c),code:n}}if(void 0===a)return{lineClassNames:{},code:n};for(var s=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return Ie(["js","jsBlock"],t);case"jsx":case"tsx":return Ie(["js","jsBlock","jsx"],t);case"html":return Ie(["js","jsBlock","html"],t);case"python":case"py":case"bash":return Ie(["bash"],t);case"markdown":case"md":return Ie(["html","jsx","bash"],t);default:return Ie(Object.keys(Se),t)}}(a,r),u=n.split("\n"),d=Object.fromEntries(r.map((function(e){return[e.className,{start:0,range:""}]}))),m=Object.fromEntries(r.filter((function(e){return e.line})).map((function(e){var t=e.className;return[e.line,t]}))),p=Object.fromEntries(r.filter((function(e){return e.block})).map((function(e){var t=e.className;return[e.block.start,t]}))),v=Object.fromEntries(r.filter((function(e){return e.block})).map((function(e){var t=e.className;return[e.block.end,t]}))),f=0;f0&&e[n-1]===t?e:e.concat(t)},Ke=function(e,t){var n=e.plain,a=Object.create(null),r=e.styles.reduce((function(e,n){var a=n.languages,r=n.style;return a&&!a.includes(t)||n.types.forEach((function(t){var n=$e({},e[t],r);e[t]=n})),e}),a);return r.root=n,r.plain=$e({},n,{backgroundColor:null}),r};function et(e,t){var n={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&-1===t.indexOf(a)&&(n[a]=e[a]);return n}const tt=function(e){function t(){for(var t=this,n=[],a=arguments.length;a--;)n[a]=arguments[a];e.apply(this,n),Ye(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?Ke(e.theme,e.language):void 0;return t.themeDict=n})),Ye(this,"getLineProps",(function(e){var n=e.key,a=e.className,r=e.style,l=$e({},et(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),o=t.getThemeDict(t.props);return void 0!==o&&(l.style=o.plain),void 0!==r&&(l.style=void 0!==l.style?$e({},l.style,r):r),void 0!==n&&(l.key=n),a&&(l.className+=" "+a),l})),Ye(this,"getStyleForToken",(function(e){var n=e.types,a=e.empty,r=n.length,l=t.getThemeDict(t.props);if(void 0!==l){if(1===r&&"plain"===n[0])return a?{display:"inline-block"}:void 0;if(1===r&&!a)return l[n[0]];var o=a?{display:"inline-block"}:{},i=n.map((function(e){return l[e]}));return Object.assign.apply(Object,[o].concat(i))}})),Ye(this,"getTokenProps",(function(e){var n=e.key,a=e.className,r=e.style,l=e.token,o=$e({},et(e,["key","className","style","token"]),{className:"token "+l.types.join(" "),children:l.content,style:t.getStyleForToken(l),key:void 0});return void 0!==r&&(o.style=void 0!==o.style?$e({},o.style,r):r),void 0!==n&&(o.key=n),a&&(o.className+=" "+a),o})),Ye(this,"tokenize",(function(e,t,n,a){var r={code:t,grammar:n,language:a,tokens:[]};e.hooks.run("before-tokenize",r);var l=r.tokens=e.tokenize(r.code,r.grammar,r.language);return e.hooks.run("after-tokenize",r),l}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,a=e.code,r=e.children,l=this.getThemeDict(this.props),o=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],a=[0],r=[e.length],l=0,o=0,i=[],c=[i];o>-1;){for(;(l=a[o]++)0?u:["plain"],s=d):(u=Xe(u,d.type),d.alias&&(u=Xe(u,d.alias)),s=d.content),"string"==typeof s){var m=s.split(Je),p=m.length;i.push({types:u,content:m[0]});for(var v=1;v0&&(i=o.getRangeAt(0)),a.append(r),r.select(),r.selectionStart=0,r.selectionEnd=e.length;var c=!1;try{c=document.execCommand("copy")}catch(s){}r.remove(),i&&(o.removeAllRanges(),o.addRange(i)),l&&l.focus()}(t),o(!0),i.current=window.setTimeout((function(){o(!1)}),1e3)}),[t]);return(0,a.useEffect)((function(){return function(){return window.clearTimeout(i.current)}}),[]),a.createElement("button",{type:"button","aria-label":l?(0,p.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,p.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,p.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,u.Z)("clean-btn",n,ot.copyButton,l&&ot.copyButtonCopied),onClick:c},a.createElement("span",{className:ot.copyButtonIcons,"aria-hidden":"true"},a.createElement("svg",{className:ot.copyButtonIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),a.createElement("svg",{className:ot.copyButtonSuccessIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const ct="wordWrapButtonIcon_Bwma",st="wordWrapButtonEnabled_EoeP";function ut(e){var t=e.className,n=e.onClick,r=e.isEnabled,l=(0,p.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return a.createElement("button",{type:"button",onClick:n,className:(0,u.Z)("clean-btn",t,r&&st),"aria-label":l,title:l},a.createElement("svg",{className:ct,viewBox:"0 0 24 24","aria-hidden":"true"},a.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function dt(e){var t,n,r,l,o,i,c,s,d,p,v,f=e.children,h=e.className,g=void 0===h?"":h,b=e.metastring,E=e.title,y=e.showLineNumbers,k=e.language,N=(0,$.L)().prism,L=N.defaultLanguage,C=N.magicComments,Z=null!=(t=null!=k?k:null==(n=g.split(" ").find((function(e){return e.startsWith("language-")})))?void 0:n.replace(/language-/,""))?t:L,T=Be(),_=(r=(0,a.useState)(!1),l=r[0],o=r[1],i=(0,a.useState)(!1),c=i[0],s=i[1],d=(0,a.useRef)(null),p=(0,a.useCallback)((function(){var e=d.current.querySelector("code");l?e.removeAttribute("style"):(e.style.whiteSpace="pre-wrap",e.style.overflowWrap="anywhere"),o((function(e){return!e}))}),[d,l]),v=(0,a.useCallback)((function(){var e=d.current,t=e.scrollWidth>e.clientWidth||d.current.querySelector("code").hasAttribute("style");s(t)}),[d]),Fe(d,v),(0,a.useEffect)((function(){v()}),[l,v]),(0,a.useEffect)((function(){return window.addEventListener("resize",v,{passive:!0}),function(){window.removeEventListener("resize",v)}}),[v]),{codeBlockRef:d,isEnabled:l,isCodeScrollable:c,toggle:p}),w=function(e){var t,n;return null!=(t=null==e||null==(n=e.match(He))?void 0:n.groups.title)?t:""}(b)||E,x=Pe(f,{metastring:b,language:Z,magicComments:C}),B=x.lineClassNames,O=x.code,j=null!=y?y:function(e){return Boolean(null==e?void 0:e.includes("showLineNumbers"))}(b);return a.createElement(Ve,{as:"div",className:(0,u.Z)(g,Z&&!g.includes("language-"+Z)&&"language-"+Z)},w&&a.createElement("div",{className:De.codeBlockTitle},w),a.createElement("div",{className:De.codeBlockContent},a.createElement(tt,(0,m.Z)({},Ge,{theme:T,code:O,language:null!=Z?Z:"text"}),(function(e){var t=e.className,n=e.tokens,r=e.getLineProps,l=e.getTokenProps;return a.createElement("pre",{tabIndex:0,ref:_.codeBlockRef,className:(0,u.Z)(t,De.codeBlock,"thin-scrollbar")},a.createElement("code",{className:(0,u.Z)(De.codeBlockLines,j&&De.codeBlockLinesWithNumbering)},n.map((function(e,t){return a.createElement(lt,{key:t,line:e,getLineProps:r,getTokenProps:l,classNames:B[t],showLineNumbers:j})}))))})),a.createElement("div",{className:De.buttonGroup},(_.isEnabled||_.isCodeScrollable)&&a.createElement(ut,{className:De.codeButton,onClick:function(){return _.toggle()},isEnabled:_.isEnabled}),a.createElement(it,{className:De.codeButton,code:O}))))}var mt=["children"];function pt(e){var t=e.children,n=(0,j.Z)(e,mt),r=(0,we.Z)(),l=function(e){return a.Children.toArray(e).some((function(e){return(0,a.isValidElement)(e)}))?e:Array.isArray(e)?e.join(""):e}(t),o="string"==typeof l?dt:Re;return a.createElement(o,(0,m.Z)({key:String(r)},n),l)}const vt="details_lb9f",ft="isBrowser_bmU9",ht="collapsibleContent_i85q";var gt=["summary","children"];function bt(e){return!!e&&("SUMMARY"===e.tagName||bt(e.parentElement))}function Et(e,t){return!!e&&(e===t||Et(e.parentElement,t))}function yt(e){var t=e.summary,n=e.children,r=(0,j.Z)(e,gt),l=(0,we.Z)(),o=(0,a.useRef)(null),i=(0,Y.u)({initialState:!r.open}),c=i.collapsed,s=i.setCollapsed,d=(0,a.useState)(r.open),p=d[0],v=d[1],f=a.isValidElement(t)?t:a.createElement("summary",null,null!=t?t:"Details");return a.createElement("details",(0,m.Z)({},r,{ref:o,open:p,"data-collapsed":c,className:(0,u.Z)(vt,l&&ft,r.className),onMouseDown:function(e){bt(e.target)&&e.detail>1&&e.preventDefault()},onClick:function(e){e.stopPropagation();var t=e.target;bt(t)&&Et(t,o.current)&&(e.preventDefault(),c?(s(!1),v(!0)):s(!0))}}),f,a.createElement(Y.z,{lazy:!1,collapsed:c,disableSSRStyle:!0,onCollapseTransitionEnd:function(e){s(e),v(!e)}},a.createElement("div",{className:ht},n)))}const kt="details_b_Ee";function Nt(e){var t=Object.assign({},(function(e){if(null==e)throw new TypeError("Cannot destructure "+e)}(e),e));return a.createElement(yt,(0,m.Z)({},t,{className:(0,u.Z)("alert alert--info",kt,t.className)}))}function Lt(e){return a.createElement(Ce,e)}const Ct="containsTaskList_mC6p";const Zt="img_ev3q";const Tt="admonition_LlT9",_t="admonitionHeading_tbUL",wt="admonitionIcon_kALy",xt="admonitionContent_S0QG";var Bt={note:{infimaClassName:"secondary",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:a.createElement(p.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:a.createElement(p.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 16 16"},a.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:a.createElement(p.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},Ot={secondary:"note",important:"info",success:"tip",warning:"danger"};function jt(e){var t,n=function(e){var t=a.Children.toArray(e),n=t.find((function(e){var t;return a.isValidElement(e)&&"mdxAdmonitionTitle"===(null==(t=e.props)?void 0:t.mdxType)})),r=a.createElement(a.Fragment,null,t.filter((function(e){return e!==n})));return{mdxAdmonitionTitle:n,rest:r}}(e.children),r=n.mdxAdmonitionTitle,l=n.rest;return Object.assign({},e,{title:null!=(t=e.title)?t:r,children:l})}const At={head:function(e){var t=a.Children.map(e.children,(function(e){return a.isValidElement(e)?function(e){var t;if(null!=(t=e.props)&&t.mdxType&&e.props.originalType){var n=e.props,r=(n.mdxType,n.originalType,(0,j.Z)(n,_e));return a.createElement(e.props.originalType,r)}return e}(e):e}));return a.createElement(Te.Z,e,t)},code:function(e){var t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return a.Children.toArray(e.children).every((function(e){var n;return"string"==typeof e&&!e.includes("\n")||(0,a.isValidElement)(e)&&t.includes(null==(n=e.props)?void 0:n.mdxType)}))?a.createElement("code",e):a.createElement(pt,e)},a:function(e){return a.createElement(v.Z,e)},pre:function(e){var t;return a.createElement(pt,(0,a.isValidElement)(e.children)&&"code"===(null==(t=e.children.props)?void 0:t.originalType)?e.children.props:Object.assign({},e))},details:function(e){var t=a.Children.toArray(e.children),n=t.find((function(e){var t;return a.isValidElement(e)&&"summary"===(null==(t=e.props)?void 0:t.mdxType)})),r=a.createElement(a.Fragment,null,t.filter((function(e){return e!==n})));return a.createElement(Nt,(0,m.Z)({},e,{summary:n}),r)},ul:function(e){return a.createElement("ul",(0,m.Z)({},e,{className:(t=e.className,(0,u.Z)(t,(null==t?void 0:t.includes("contains-task-list"))&&Ct))}));var t},img:function(e){return a.createElement("img",(0,m.Z)({loading:"lazy"},e,{className:(t=e.className,(0,u.Z)(t,Zt))}));var t},h1:function(e){return a.createElement(Lt,(0,m.Z)({as:"h1"},e))},h2:function(e){return a.createElement(Lt,(0,m.Z)({as:"h2"},e))},h3:function(e){return a.createElement(Lt,(0,m.Z)({as:"h3"},e))},h4:function(e){return a.createElement(Lt,(0,m.Z)({as:"h4"},e))},h5:function(e){return a.createElement(Lt,(0,m.Z)({as:"h5"},e))},h6:function(e){return a.createElement(Lt,(0,m.Z)({as:"h6"},e))},admonition:function(e){var t=jt(e),n=t.children,r=t.type,l=t.title,o=t.icon,i=function(e){var t,n=null!=(t=Ot[e])?t:e,a=Bt[n];return a||(console.warn('No admonition config found for admonition type "'+n+'". Using Info as fallback.'),Bt.info)}(r),c=null!=l?l:i.label,s=i.iconComponent,d=null!=o?o:a.createElement(s,null);return a.createElement("div",{className:(0,u.Z)(y.k.common.admonition,y.k.common.admonitionType(e.type),"alert","alert--"+i.infimaClassName,Tt)},a.createElement("div",{className:_t},a.createElement("span",{className:wt},d),c),a.createElement("div",{className:xt},n))},mermaid:n(1875).Z};function Ht(e){var t=e.children;return a.createElement(Ze.Zo,{components:At},t)}function Mt(e){var t,n,r,l,o=e.children,i=(t=c(),n=t.metadata,r=t.frontMatter,l=t.contentTitle,r.hide_title||void 0!==l?null:n.title);return a.createElement("div",{className:(0,u.Z)(y.k.docs.docMarkdown,"markdown")},i&&a.createElement("header",null,a.createElement(Ce,{as:"h1"},i)),a.createElement(Ht,null,o))}var St=n(3651),It=n(8596),Pt=n(4996);function Ut(e){return a.createElement("svg",(0,m.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const zt="breadcrumbHomeIcon_YNFT";function Vt(){var e=(0,Pt.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(v.Z,{"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(Ut,{className:zt})))}const Dt="breadcrumbsContainer_Z_bl";function Rt(e){var t=e.children,n=e.href,r="breadcrumbs__link";return e.isLast?a.createElement("span",{className:r,itemProp:"name"},t):n?a.createElement(v.Z,{className:r,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:r},t)}function Wt(e){var t=e.children,n=e.active,r=e.index,l=e.addMicrodata;return a.createElement("li",(0,m.Z)({},l&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,u.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(r+1)}))}function Ft(){var e=(0,St.s1)(),t=(0,It.Ns)();return e?a.createElement("nav",{className:(0,u.Z)(y.k.docs.docBreadcrumbs,Dt),"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(Vt,null),e.map((function(t,n){var r=n===e.length-1;return a.createElement(Wt,{key:n,active:r,index:n,addMicrodata:!!t.href},a.createElement(Rt,{href:t.href,isLast:r},t.label))})))):null}const qt="docItemContainer_Djhp",Gt="docItemCol_VOVn";function Yt(e){var t,n,r,l,o,i,s=e.children,m=(t=c(),n=t.frontMatter,r=t.toc,l=(0,d.i)(),o=n.hide_table_of_contents,i=!o&&r.length>0,{hidden:o,mobile:i?a.createElement(he,null):void 0,desktop:!i||"desktop"!==l&&"ssr"!==l?void 0:a.createElement(ye,null)});return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,u.Z)("col",!m.hidden&&Gt)},a.createElement(_,null),a.createElement("div",{className:qt},a.createElement("article",null,a.createElement(Ft,null),a.createElement(w,null),m.mobile,a.createElement(Mt,null,s),a.createElement(G,null)),a.createElement(g,null))),m.desktop&&a.createElement("div",{className:"col col--3"},m.desktop))}function $t(e){var t="docs-doc-id-"+e.content.metadata.unversionedId,n=e.content;return a.createElement(i,{content:e.content},a.createElement(r.FG,{className:t},a.createElement(s,null),a.createElement(Yt,null,a.createElement(n,null))))}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>i,q:()=>o});var a=n(7294),r=n(4700),l=a.createContext(null);function o(e){var t=e.children,n=e.version;return a.createElement(l.Provider,{value:n},t)}function i(){var e=(0,a.useContext)(l);if(null===e)throw new r.i6("DocsVersionProvider");return e}},7594:(e,t)=>{function n(e){let t,n=[];for(let a of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(a))n.push(parseInt(a,10));else if(t=a.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,a,r,l]=t;if(a&&l){a=parseInt(a),l=parseInt(l);const e=a{n.r(t),n.d(t,{default:()=>xe});var a=n(7294),r=n(6010),l=n(1944),i=n(5281),o=n(3320),c=n(3651),s=n(4477),d=n(1116),m=n(7961),u=n(5999),b=n(2466),p=n(5936);const v="backToTopButton_sjWU",h="backToTopButtonShow_xfvO";function E(){var e=function(e){var t=e.threshold,n=(0,a.useState)(!1),r=n[0],l=n[1],i=(0,a.useRef)(!1),o=(0,b.Ct)(),c=o.startScroll,s=o.cancelScroll;return(0,b.RF)((function(e,n){var a=e.scrollY,r=null==n?void 0:n.scrollY;r&&(i.current?i.current=!1:a>=r?(s(),l(!1)):a{n.r(t),n.d(t,{default:()=>o});var a=n(7294),r=n(5999),l=n(1944),i=n(7961);function o(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,r.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(i.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(r.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(r.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(r.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>o,q:()=>i});var a=n(7294),r=n(4700),l=a.createContext(null);function i(e){var t=e.children,n=e.version;return a.createElement(l.Provider,{value:n},t)}function o(){var e=(0,a.useContext)(l);if(null===e)throw new r.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/zh-CN/assets/js/283536cd.3445ba73.js b/zh-CN/assets/js/283536cd.3445ba73.js new file mode 100644 index 00000000..ad432ccf --- /dev/null +++ b/zh-CN/assets/js/283536cd.3445ba73.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[391],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>k});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function m(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var p=a.createContext({}),o=function(e){var t=a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=o(e.components);return a.createElement(p.Provider,{value:t},e.children)},c="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,m=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=o(r),d=n,k=c["".concat(p,".").concat(d)]||c[d]||s[d]||m;return r?a.createElement(k,i(i({ref:t},u),{},{components:r})):a.createElement(k,i({ref:t},u))}));function k(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var m=r.length,i=new Array(m);i[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[c]="string"==typeof e?e:n,i[1]=l;for(var o=2;o{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var a=r(3117),n=r(102),m=(r(7294),r(3905)),i=["components"],l={id:"introduction",title:"Immer \u5165\u95e8",sidebar_label:"\u5165\u95e8",slug:"/"},p=void 0,o={unversionedId:"introduction",id:"introduction",title:"Immer \u5165\u95e8",description:"2019 \u5e74 \u201c\u5e74\u5ea6\u7a81\u7834\u201dReact \u5f00\u6e90\u5956\u548c\u201c\u6700\u6709\u5f71\u54cd\u7684\u8d21\u732e\u201dJavaScript \u5f00\u6e90\u5956\u7684\u83b7\u5f97\u8005",source:"@site/i18n/zh-CN/docusaurus-plugin-content-docs/current/introduction.md",sourceDirName:".",slug:"/",permalink:"/immer/zh-CN/",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/introduction.md",tags:[],version:"current",frontMatter:{id:"introduction",title:"Immer \u5165\u95e8",sidebar_label:"\u5165\u95e8",slug:"/"},sidebar:"Immer",next:{title:"\u5b89\u88c5",permalink:"/immer/zh-CN/installation"}},u={},c=[{value:"Immer \u7b80\u5316\u4e86\u4e0d\u53ef\u53d8\u6570\u636e\u7ed3\u6784\u7684\u5904\u7406",id:"immer-\u7b80\u5316\u4e86\u4e0d\u53ef\u53d8\u6570\u636e\u7ed3\u6784\u7684\u5904\u7406",level:3},{value:"\u4e00\u4e2a\u7b80\u5355\u7684\u6bd4\u8f83\u793a\u4f8b",id:"\u4e00\u4e2a\u7b80\u5355\u7684\u6bd4\u8f83\u793a\u4f8b",level:3},{value:"\u4e0d\u4f7f\u7528 Immer",id:"\u4e0d\u4f7f\u7528-immer",level:4},{value:"\u4f7f\u7528 Immer",id:"\u4f7f\u7528-immer",level:4},{value:"Immer \u5982\u4f55\u5de5\u4f5c",id:"immer-\u5982\u4f55\u5de5\u4f5c",level:3},{value:"\u597d\u5904",id:"\u597d\u5904",level:2}],s={toc:c};function d(e){var t=e.components,l=(0,n.Z)(e,i);return(0,m.kt)("wrapper",(0,a.Z)({},s,l,{components:t,mdxType:"MDXLayout"}),(0,m.kt)("center",null,(0,m.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",class:"horizontal bordered"})),(0,m.kt)("img",{src:"/immer/img/immer-logo.svg",height:"200px",align:"right"}),(0,m.kt)("h1",{id:"immer"},"Immer"),(0,m.kt)("p",null,"2019 \u5e74 \u201c\u5e74\u5ea6\u7a81\u7834\u201d",(0,m.kt)("a",{parentName:"p",href:"https://osawards.com/react/"},"React \u5f00\u6e90\u5956"),"\u548c\u201c\u6700\u6709\u5f71\u54cd\u7684\u8d21\u732e\u201d",(0,m.kt)("a",{parentName:"p",href:"https://osawards.com/javascript/"},"JavaScript \u5f00\u6e90\u5956"),"\u7684\u83b7\u5f97\u8005"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},"\u4ecb\u7ecd\u535a\u5ba2: ",(0,m.kt)("a",{parentName:"li",href:"https://medium.com/@mweststrate/introducing-immer-immutability-the-easy-way-9d73d8f71cb3"},"Immer: Immutability the easy way")),(0,m.kt)("li",{parentName:"ul"},"Egghead.io \u7b80\u77ed\u8bfe\u7a0b\uff0c\u6db5\u76d6 Immer \u7684\u57fa\u672c\u77e5\u8bc6: ",(0,m.kt)("a",{parentName:"li",href:"https://egghead.io/lessons/redux-simplify-creating-immutable-data-trees-with-immer"},"Simplify creating immutable data trees with Immer (7 \u5206\u949f)")),(0,m.kt)("li",{parentName:"ul"},"Egghead.io \u514d\u8d39\u6df1\u5165\u8bfe\u7a0b: ",(0,m.kt)("a",{parentName:"li",href:"https://egghead.io/courses/immutable-javascript-data-structures-with-immer"},"Immutable JavaScript Data Structures with Immer (58 \u5206\u949f)"))),(0,m.kt)("hr",null),(0,m.kt)("p",null,"Immer\uff08\u5fb7\u8bed\u4e3a\uff1aalways\uff09\u662f\u4e00\u4e2a\u5c0f\u578b\u5305\uff0c\u53ef\u8ba9\u60a8\u4ee5\u66f4\u65b9\u4fbf\u7684\u65b9\u5f0f\u4f7f\u7528\u4e0d\u53ef\u53d8\u72b6\u6001\u3002"),(0,m.kt)("h3",{id:"immer-\u7b80\u5316\u4e86\u4e0d\u53ef\u53d8\u6570\u636e\u7ed3\u6784\u7684\u5904\u7406"},"Immer \u7b80\u5316\u4e86\u4e0d\u53ef\u53d8\u6570\u636e\u7ed3\u6784\u7684\u5904\u7406"),(0,m.kt)("p",null,"Immer \u53ef\u4ee5\u5728\u9700\u8981\u4f7f\u7528\u4e0d\u53ef\u53d8\u6570\u636e\u7ed3\u6784\u7684\u4efb\u4f55\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u3002\u4f8b\u5982\u4e0e React state\u3001React \u6216 Redux reducers \u6216\u8005 configuration management \u7ed3\u5408\u4f7f\u7528\u3002\u4e0d\u53ef\u53d8\u7684\u6570\u636e\u7ed3\u6784\u5141\u8bb8\uff08\u9ad8\u6548\uff09\u7684\u53d8\u5316\u68c0\u6d4b\uff1a\u5982\u679c\u5bf9\u5bf9\u8c61\u7684\u5f15\u7528\u6ca1\u6709\u6539\u53d8\uff0c\u90a3\u4e48\u5bf9\u8c61\u672c\u8eab\u4e5f\u6ca1\u6709\u6539\u53d8\u3002\u6b64\u5916\uff0c\u5b83\u4f7f\u514b\u9686\u5bf9\u8c61\u76f8\u5bf9\u4fbf\u5b9c\uff1a\u6570\u636e\u6811\u7684\u672a\u66f4\u6539\u90e8\u5206\u4e0d\u9700\u8981\u590d\u5236\uff0c\u5e76\u4e14\u5728\u5185\u5b58\u4e2d\u4e0e\u76f8\u540c\u72b6\u6001\u7684\u65e7\u7248\u672c\u5171\u4eab"),(0,m.kt)("p",null,"\u4e00\u822c\u6765\u8bf4\uff0c\u8fd9\u4e9b\u597d\u5904\u53ef\u4ee5\u901a\u8fc7\u786e\u4fdd\u60a8\u6c38\u8fdc\u4e0d\u4f1a\u66f4\u6539\u5bf9\u8c61\u3001\u6570\u7ec4\u6216\u6620\u5c04\u7684\u4efb\u4f55\u5c5e\u6027\u6765\u5b9e\u73b0\uff0c\u800c\u662f\u59cb\u7ec8\u521b\u5efa\u4e00\u4e2a\u66f4\u6539\u540e\u7684\u526f\u672c\u3002\u5728\u5b9e\u8df5\u4e2d\uff0c\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u4ee3\u7801\u7f16\u5199\u8d77\u6765\u975e\u5e38\u9ebb\u70e6\uff0c\u5e76\u4e14\u5f88\u5bb9\u6613\u610f\u5916\u8fdd\u53cd\u8fd9\u4e9b\u7ea6\u675f\u3002 Immer \u5c06\u901a\u8fc7\u89e3\u51b3\u4ee5\u4e0b\u75db\u70b9\u6765\u5e2e\u52a9\u60a8\u9075\u5faa\u4e0d\u53ef\u53d8\u6570\u636e\u8303\u5f0f\uff1a"),(0,m.kt)("ol",null,(0,m.kt)("li",{parentName:"ol"},"Immer \u5c06\u68c0\u6d4b\u5230\u610f\u5916 mutations \u5e76\u629b\u51fa\u9519\u8bef\u3002"),(0,m.kt)("li",{parentName:"ol"},"Immer \u5c06\u4e0d\u518d\u9700\u8981\u521b\u5efa\u5bf9\u4e0d\u53ef\u53d8\u5bf9\u8c61\u8fdb\u884c\u6df1\u5ea6\u66f4\u65b0\u65f6\u6240\u9700\u7684\u5178\u578b\u6837\u677f\u4ee3\u7801\uff1a\u5982\u679c\u6ca1\u6709 Immer\uff0c\u5219\u9700\u8981\u5728\u6bcf\u4e2a\u7ea7\u522b\u624b\u52a8\u5236\u4f5c\u5bf9\u8c61\u526f\u672c\u3002\u901a\u5e38\u901a\u8fc7\u4f7f\u7528\u5927\u91cf ",(0,m.kt)("inlineCode",{parentName:"li"},"...")," \u5c55\u5f00\u64cd\u4f5c\u3002\u4f7f\u7528 Immer \u65f6\uff0c\u4f1a\u5bf9 ",(0,m.kt)("inlineCode",{parentName:"li"},"draft")," \u5bf9\u8c61\u8fdb\u884c\u66f4\u6539\uff0c\u8be5\u5bf9\u8c61\u4f1a\u8bb0\u5f55\u66f4\u6539\u5e76\u8d1f\u8d23\u521b\u5efa\u5fc5\u8981\u7684\u526f\u672c\uff0c\u800c\u4e0d\u4f1a\u5f71\u54cd\u539f\u59cb\u5bf9\u8c61\u3002"),(0,m.kt)("li",{parentName:"ol"},"\u4f7f\u7528 Immer \u65f6\uff0c\u60a8\u65e0\u9700\u5b66\u4e60\u4e13\u7528 API \u6216\u6570\u636e\u7ed3\u6784\u5373\u53ef\u4ece\u8303\u4f8b\u4e2d\u53d7\u76ca\u3002\u4f7f\u7528 Immer\uff0c\u60a8\u5c06\u4f7f\u7528\u7eaf JavaScript \u6570\u636e\u7ed3\u6784\uff0c\u5e76\u4f7f\u7528\u4f17\u6240\u5468\u77e5\u7684\u5b89\u5168\u5730\u53ef\u53d8 JavaScript API\u3002")),(0,m.kt)("h3",{id:"\u4e00\u4e2a\u7b80\u5355\u7684\u6bd4\u8f83\u793a\u4f8b"},"\u4e00\u4e2a\u7b80\u5355\u7684\u6bd4\u8f83\u793a\u4f8b"),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-javascript"},'const baseState = [\n {\n title: "Learn TypeScript",\n done: true\n },\n {\n title: "Try Immer",\n done: false\n }\n]\n')),(0,m.kt)("p",null,"\u5047\u8bbe\u6211\u4eec\u6709\u4e0a\u8ff0\u57fa\u672c\u72b6\u6001\uff0c\u6211\u4eec\u9700\u8981\u66f4\u65b0\u7b2c\u4e8c\u4e2a todo\uff0c\u5e76\u6dfb\u52a0\u7b2c\u4e09\u4e2a\u3002\u4f46\u662f\uff0c\u6211\u4eec\u4e0d\u60f3\u6539\u53d8\u539f\u59cb\u7684 baseState\uff0c\u6211\u4eec\u4e5f\u60f3\u907f\u514d\u6df1\u5ea6\u514b\u9686\uff08\u4ee5\u4fdd\u7559\u7b2c\u4e00\u4e2a todo\uff09"),(0,m.kt)("h4",{id:"\u4e0d\u4f7f\u7528-immer"},"\u4e0d\u4f7f\u7528 Immer"),(0,m.kt)("p",null,"\u5982\u679c\u6ca1\u6709 Immer\uff0c\u6211\u4eec\u5c06\u4e0d\u5f97\u4e0d\u5c0f\u5fc3\u5730\u6d45\u62f7\u8d1d\u6bcf\u5c42\u53d7\u6211\u4eec\u66f4\u6539\u5f71\u54cd\u7684 state \u7ed3\u6784"),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-javascript"},'const nextState = baseState.slice() // \u6d45\u62f7\u8d1d\u6570\u7ec4\nnextState[1] = {\n // \u66ff\u6362\u7b2c\u4e00\u5c42\u5143\u7d20\n ...nextState[1], // \u6d45\u62f7\u8d1d\u7b2c\u4e00\u5c42\u5143\u7d20\n done: true // \u671f\u671b\u7684\u66f4\u65b0\n}\n// \u56e0\u4e3a nextState \u662f\u65b0\u62f7\u8d1d\u7684, \u6240\u4ee5\u4f7f\u7528 push \u65b9\u6cd5\u662f\u5b89\u5168\u7684,\n// \u4f46\u662f\u5728\u672a\u6765\u7684\u4efb\u610f\u65f6\u95f4\u505a\u76f8\u540c\u7684\u4e8b\u60c5\u4f1a\u8fdd\u53cd\u4e0d\u53d8\u6027\u539f\u5219\u5e76\u4e14\u5bfc\u81f4 bug\uff01\nnextState.push({title: "Tweet about it"})\n')),(0,m.kt)("h4",{id:"\u4f7f\u7528-immer"},"\u4f7f\u7528 Immer"),(0,m.kt)("p",null,"\u4f7f\u7528 Immer\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u66f4\u52a0\u7b80\u5355\u3002\u6211\u4eec\u53ef\u4ee5\u5229\u7528 ",(0,m.kt)("inlineCode",{parentName:"p"},"produce")," \u51fd\u6570\uff0c\u5b83\u5c06\u6211\u4eec\u8981\u66f4\u6539\u7684 state \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u5bf9\u4e8e\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff0c\u6211\u4eec\u4f20\u9012\u4e00\u4e2a\u540d\u4e3a recipe \u7684\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u4f20\u9012\u4e00\u4e2a ",(0,m.kt)("inlineCode",{parentName:"p"},"draft")," \u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5176\u5e94\u7528\u76f4\u63a5\u7684 ",(0,m.kt)("inlineCode",{parentName:"p"},"mutations"),"\u3002\u4e00\u65e6 ",(0,m.kt)("inlineCode",{parentName:"p"},"recipe")," \u6267\u884c\u5b8c\u6210\uff0c\u8fd9\u4e9b ",(0,m.kt)("inlineCode",{parentName:"p"},"mutations")," \u88ab\u8bb0\u5f55\u5e76\u7528\u4e8e\u4ea7\u751f\u4e0b\u4e00\u4e2a\u72b6\u6001\u3002 ",(0,m.kt)("inlineCode",{parentName:"p"},"produce")," \u5c06\u8d1f\u8d23\u6240\u6709\u5fc5\u8981\u7684\u590d\u5236\uff0c\u5e76\u901a\u8fc7\u51bb\u7ed3\u6570\u636e\u6765\u9632\u6b62\u672a\u6765\u7684\u610f\u5916\u4fee\u6539\u3002"),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst nextState = produce(baseState, draft => {\n draft[1].done = true\n draft.push({title: "Tweet about it"})\n})\n')),(0,m.kt)("p",null,"\u6b63\u5728\u5bfb\u627e\u7ed3\u5408 React \u7684 Immer\uff1f\u8df3\u5230 ",(0,m.kt)("a",{parentName:"p",href:"example-setstate"},"React + Immer")," \u9875\u9762"),(0,m.kt)("h3",{id:"immer-\u5982\u4f55\u5de5\u4f5c"},"Immer \u5982\u4f55\u5de5\u4f5c"),(0,m.kt)("p",null,"\u57fa\u672c\u601d\u60f3\u662f\uff0c\u4f7f\u7528 Immer\uff0c\u60a8\u4f1a\u5c06\u6240\u6709\u66f4\u6539\u5e94\u7528\u5230\u4e34\u65f6 ",(0,m.kt)("em",{parentName:"p"},"draft"),"\uff0c\u5b83\u662f ",(0,m.kt)("em",{parentName:"p"},"currentState")," \u7684\u4ee3\u7406\u3002\u4e00\u65e6\u4f60\u5b8c\u6210\u4e86\u6240\u6709\u7684 ",(0,m.kt)("em",{parentName:"p"},"mutations"),"\uff0cImmer \u5c06\u6839\u636e\u5bf9 ",(0,m.kt)("em",{parentName:"p"},"draft state")," \u7684 ",(0,m.kt)("em",{parentName:"p"},"mutations")," \u751f\u6210 nextState\u3002\u8fd9\u610f\u5473\u7740\u60a8\u53ef\u4ee5\u901a\u8fc7\u7b80\u5355\u5730\u4fee\u6539\u6570\u636e\u6765\u4e0e\u6570\u636e\u4ea4\u4e92\uff0c\u540c\u65f6\u4fdd\u7559\u4e0d\u53ef\u53d8\u6570\u636e\u7684\u6240\u6709\u597d\u5904\u3002"),(0,m.kt)("p",null,(0,m.kt)("img",{alt:"immer-hd.png",src:r(9795).Z,width:"1400",height:"544"})),(0,m.kt)("p",null,"\u4f7f\u7528 Immer \u5c31\u50cf\u62e5\u6709\u4e00\u4e2a\u79c1\u4eba\u52a9\u7406\u3002\u52a9\u624b\u62ff\u4e00\u5c01\u4fe1\uff08\u5f53\u524d\u72b6\u6001\uff09\u5e76\u7ed9\u60a8\u4e00\u4efd\u526f\u672c\uff08\u8349\u7a3f\uff09\u4ee5\u8bb0\u5f55\u66f4\u6539\u3002\u5b8c\u6210\u540e\uff0c\u52a9\u624b\u5c06\u63a5\u53d7\u60a8\u7684\u8349\u7a3f\u5e76\u4e3a\u60a8\u751f\u6210\u771f\u6b63\u4e0d\u53d8\u7684\u6700\u7ec8\u5b57\u6bcd\uff08\u4e0b\u4e00\u4e2a\u72b6\u6001\uff09\u3002"),(0,m.kt)("p",null,"\u524d\u5f80 ",(0,m.kt)("a",{parentName:"p",href:"/immer/zh-CN/produce"},"\u4e0b\u4e00\u7ae0\u8282")," \u4ee5\u8fdb\u4e00\u6b65\u6df1\u5165\u4e86\u89e3 ",(0,m.kt)("inlineCode",{parentName:"p"},"produce")),(0,m.kt)("h2",{id:"\u597d\u5904"},"\u597d\u5904"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},'\u9075\u5faa\u4e0d\u53ef\u53d8\u6570\u636e\u8303\u5f0f\uff0c\u540c\u65f6\u4f7f\u7528\u666e\u901a\u7684 JavaScript \u5bf9\u8c61\u3001\u6570\u7ec4\u3001Sets \u548c Maps\u3002\u65e0\u9700\u5b66\u4e60\u65b0\u7684 API \u6216 "mutations patterns"\uff01'),(0,m.kt)("li",{parentName:"ul"},"\u5f3a\u7c7b\u578b\uff0c\u65e0\u57fa\u4e8e\u5b57\u7b26\u4e32\u7684\u8def\u5f84\u9009\u62e9\u5668\u7b49"),(0,m.kt)("li",{parentName:"ul"},"\u5f00\u7bb1\u5373\u7528\u7684\u7ed3\u6784\u5171\u4eab"),(0,m.kt)("li",{parentName:"ul"},"\u5f00\u7bb1\u5373\u7528\u7684\u5bf9\u8c61\u51bb\u7ed3"),(0,m.kt)("li",{parentName:"ul"},"\u6df1\u5ea6\u66f4\u65b0\u8f7b\u800c\u6613\u4e3e"),(0,m.kt)("li",{parentName:"ul"},"\u6837\u677f\u4ee3\u7801\u51cf\u5c11\u3002\u66f4\u5c11\u7684\u566a\u97f3\uff0c\u66f4\u7b80\u6d01\u7684\u4ee3\u7801"),(0,m.kt)("li",{parentName:"ul"},"\u5bf9 JSON \u8865\u4e01\u7684\u4e00\u6d41\u652f\u6301"),(0,m.kt)("li",{parentName:"ul"},"\u5c0f\uff1a3KB gzip")))}d.isMDXComponent=!0},9795:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/immer-4002b3fd2cfd3aa66c62ecc525663c0d.png"}}]); \ No newline at end of file diff --git a/zh-CN/assets/js/2a403987.1f5bea41.js b/zh-CN/assets/js/2a403987.1f5bea41.js new file mode 100644 index 00000000..5f29bdf6 --- /dev/null +++ b/zh-CN/assets/js/2a403987.1f5bea41.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[463],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),m=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=m(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),u=m(r),f=o,d=u["".concat(c,".").concat(f)]||u[f]||s[f]||i;return r?n.createElement(d,a(a({ref:t},l),{},{components:r})):n.createElement(d,a({ref:t},l))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:o,a[1]=p;for(var m=2;m{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>p,metadata:()=>m,toc:()=>u});var n=r(3117),o=r(102),i=(r(7294),r(3905)),a=["components"],p={id:"support",title:"\u8d5e\u52a9 immer"},c=void 0,m={unversionedId:"support",id:"support",title:"\u8d5e\u52a9 immer",description:"Immer \u76ee\u524d\u5728 GitHub \u4e0a\u6709 350000 \u4e2a\u9879\u76ee\u4f9d\u8d56\u4e8e\u5b83\uff0c\u6bcf\u6708\u7684\u4e0b\u8f7d\u91cf\u63a5\u8fd1 10000000 \u6b21\u3002\u7136\u800c\uff0c\u53ea\u6709\u4e00\u5f00\u59cb\u4e24\u5929\u7684\u5f00\u53d1\u5f97\u5230\u4e86\u8d5e\u52a9\uff08\u7531 Mendix\uff09\uff0c\u4e4b\u540e\u7684\u6240\u6709\u5f00\u53d1\u548c\u7ef4\u62a4\u90fd\u662f\u7528\u7231\u53d1\u7535\u3002",source:"@site/i18n/zh-CN/docusaurus-plugin-content-docs/current/support.md",sourceDirName:".",slug:"/support",permalink:"/immer/zh-CN/support",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/support.md",tags:[],version:"current",frontMatter:{id:"support",title:"\u8d5e\u52a9 immer"},sidebar:"Immer",previous:{title:"\u57fa\u4e8e Immer",permalink:"/immer/zh-CN/built-with"},next:{title:"\u79fb\u690d\u5230\u5176\u5b83\u8bed\u8a00",permalink:"/immer/zh-CN/other-lang"}},l={},u=[],s={toc:u};function f(e){var t=e.components,r=(0,o.Z)(e,a);return(0,i.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("center",null,(0,i.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",class:"horizontal bordered"})),(0,i.kt)("p",null,"Immer \u76ee\u524d\u5728 GitHub \u4e0a\u6709 350000 \u4e2a\u9879\u76ee\u4f9d\u8d56\u4e8e\u5b83\uff0c\u6bcf\u6708\u7684\u4e0b\u8f7d\u91cf\u63a5\u8fd1 10000000 \u6b21\u3002\u7136\u800c\uff0c\u53ea\u6709\u4e00\u5f00\u59cb\u4e24\u5929\u7684\u5f00\u53d1\u5f97\u5230\u4e86\u8d5e\u52a9\uff08\u7531 Mendix\uff09\uff0c\u4e4b\u540e\u7684\u6240\u6709\u5f00\u53d1\u548c\u7ef4\u62a4\u90fd\u662f\u7528\u7231\u53d1\u7535\u3002"),(0,i.kt)("p",null,"\u5982\u679c\u60a8\u559c\u6b22 Immer\uff0c\u5e76\u4e14\u5bf9\u8fd9\u4e2a\u5305\u5fc3\u5b58\u611f\u6fc0\uff0c\u6216\u8005\u60f3\u786e\u4fdd\u5b83\u7684\u4f7f\u7528\u5bff\u547d\uff0c\u8bf7\u8003\u8651\u5728 ",(0,i.kt)("a",{parentName:"p",href:"https://opencollective.com/immer"},"https://opencollective.com/immer")," \u4e0a\u8d5e\u52a9\u6216\u4f7f\u7528 ",(0,i.kt)("a",{parentName:"p",href:"https://www.paypal.me/michelweststrate"},"PayPal")," \u8fdb\u884c\u4e00\u6b21\u6027\u6350\u8d60\u3002"))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/zh-CN/assets/js/31e1f126.560507e5.js b/zh-CN/assets/js/31e1f126.560507e5.js new file mode 100644 index 00000000..fba16251 --- /dev/null +++ b/zh-CN/assets/js/31e1f126.560507e5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[803],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function d(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",l={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,d=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),f=o,m=u["".concat(i,".").concat(f)]||u[f]||l[f]||d;return n?r.createElement(m,a(a({ref:t},c),{},{components:n})):r.createElement(m,a({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var d=n.length,a=new Array(d);a[0]=f;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>s,metadata:()=>p,toc:()=>u});var r=n(3117),o=n(102),d=(n(7294),n(3905)),a=["components"],s={id:"update-patterns",title:"\u66f4\u65b0\u6a21\u5f0f"},i=void 0,p={unversionedId:"update-patterns",id:"update-patterns",title:"\u66f4\u65b0\u6a21\u5f0f",description:"\u5728 Immer \u4e4b\u524d\uff0c\u4f7f\u7528\u4e0d\u53ef\u53d8\u6570\u636e\u610f\u5473\u7740\u5b66\u4e60\u6240\u6709\u4e0d\u53ef\u53d8\u7684\u66f4\u65b0\u6a21\u5f0f\u3002",source:"@site/i18n/zh-CN/docusaurus-plugin-content-docs/current/update-patterns.md",sourceDirName:".",slug:"/update-patterns",permalink:"/immer/zh-CN/update-patterns",draft:!1,editUrl:"https://github.com/immerjs/immer/edit/main/website/docs/update-patterns.md",tags:[],version:"current",frontMatter:{id:"update-patterns",title:"\u66f4\u65b0\u6a21\u5f0f"},sidebar:"Immer",previous:{title:"React & Immer",permalink:"/immer/zh-CN/example-setstate"},next:{title:"API \u6982\u89c8",permalink:"/immer/zh-CN/api"}},c={},u=[{value:"\u66f4\u65b0\u5bf9\u8c61",id:"\u66f4\u65b0\u5bf9\u8c61",level:3},{value:"\u66f4\u65b0\u6570\u7ec4",id:"\u66f4\u65b0\u6570\u7ec4",level:3},{value:"\u5d4c\u5957\u6570\u636e\u7ed3\u6784",id:"\u5d4c\u5957\u6570\u636e\u7ed3\u6784",level:3}],l={toc:u};function f(e){var t=e.components,n=(0,o.Z)(e,a);return(0,d.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,d.kt)("center",null,(0,d.kt)("div",{"data-ea-publisher":"immerjs","data-ea-type":"image",class:"horizontal bordered"})),(0,d.kt)("p",null,"\u5728 Immer \u4e4b\u524d\uff0c\u4f7f\u7528\u4e0d\u53ef\u53d8\u6570\u636e\u610f\u5473\u7740\u5b66\u4e60\u6240\u6709\u4e0d\u53ef\u53d8\u7684\u66f4\u65b0\u6a21\u5f0f\u3002"),(0,d.kt)("p",null,"\u4e3a\u4e86\u5e2e\u52a9\u201c\u5fd8\u8bb0\u201d\u8fd9\u4e9b\u6a21\u5f0f\uff0c\u8fd9\u91cc\u6982\u8ff0\u4e86\u5982\u4f55\u5229\u7528\u5185\u7f6e JavaScript API \u6765\u66f4\u65b0\u5bf9\u8c61\u548c\u96c6\u5408"),(0,d.kt)("h3",{id:"\u66f4\u65b0\u5bf9\u8c61"},"\u66f4\u65b0\u5bf9\u8c61"),(0,d.kt)("pre",null,(0,d.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst todosObj = {\n id1: {done: false, body: "Take out the trash"},\n id2: {done: false, body: "Check Email"}\n}\n\n// \u6dfb\u52a0\nconst addedTodosObj = produce(todosObj, draft => {\n draft["id3"] = {done: false, body: "Buy bananas"}\n})\n\n// \u5220\u9664\nconst deletedTodosObj = produce(todosObj, draft => {\n delete draft["id1"]\n})\n\n// \u66f4\u65b0\nconst updatedTodosObj = produce(todosObj, draft => {\n draft["id1"].done = true\n})\n')),(0,d.kt)("h3",{id:"\u66f4\u65b0\u6570\u7ec4"},"\u66f4\u65b0\u6570\u7ec4"),(0,d.kt)("pre",null,(0,d.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\nconst todosArray = [\n {id: "id1", done: false, body: "Take out the trash"},\n {id: "id2", done: false, body: "Check Email"}\n]\n\n// \u6dfb\u52a0\nconst addedTodosArray = produce(todosArray, draft => {\n draft.push({id: "id3", done: false, body: "Buy bananas"})\n})\n\n// \u7d22\u5f15\u5220\u9664\nconst deletedTodosArray = produce(todosArray, draft => {\n draft.splice(3 /*\u7d22\u5f15 */, 1)\n})\n\n// \u7d22\u5f15\u66f4\u65b0\nconst updatedTodosArray = produce(todosArray, draft => {\n draft[3].done = true\n})\n\n// \u7d22\u5f15\u63d2\u5165\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.splice(3, 0, {id: "id3", done: false, body: "Buy bananas"})\n})\n\n// \u5220\u9664\u6700\u540e\u4e00\u4e2a\u5143\u7d20\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.pop()\n})\n\n// \u5220\u9664\u7b2c\u4e00\u4e2a\u5143\u7d20\nconst updatedTodosArray = produce(todosArray, draft => {\n draft.shift()\n})\n\n// \u6570\u7ec4\u5f00\u5934\u6dfb\u52a0\u5143\u7d20\nconst addedTodosArray = produce(todosArray, draft => {\n draft.unshift({id: "id3", done: false, body: "Buy bananas"})\n})\n\n// \u6839\u636e id \u5220\u9664\nconst deletedTodosArray = produce(todosArray, draft => {\n const index = draft.findIndex(todo => todo.id === "id1")\n if (index !== -1) draft.splice(index, 1)\n})\n\n// \u6839\u636e id \u66f4\u65b0\nconst updatedTodosArray = produce(todosArray, draft => {\n const index = draft.findIndex(todo => todo.id === "id1")\n if (index !== -1) draft[index].done = true\n})\n\n// \u8fc7\u6ee4\nconst updatedTodosArray = produce(todosArray, draft => {\n // \u8fc7\u6ee4\u5668\u5b9e\u9645\u4e0a\u4f1a\u8fd4\u56de\u4e00\u4e2a\u4e0d\u53ef\u53d8\u7684\u72b6\u6001\uff0c\u4f46\u662f\u5982\u679c\u8fc7\u6ee4\u5668\u4e0d\u662f\u5904\u4e8e\u5bf9\u8c61\u7684\u9876\u5c42\uff0c\u8fd9\u4e2a\u4f9d\u7136\u5f88\u6709\u7528\n return draft.filter(todo => todo.done)\n})\n')),(0,d.kt)("h3",{id:"\u5d4c\u5957\u6570\u636e\u7ed3\u6784"},"\u5d4c\u5957\u6570\u636e\u7ed3\u6784"),(0,d.kt)("pre",null,(0,d.kt)("code",{parentName:"pre",className:"language-javascript"},'import {produce} from "immer"\n\n// \u590d\u6742\u6570\u636e\u7ed3\u6784\u4f8b\u5b50\nconst store = {\n users: new Map([\n [\n "17",\n {\n name: "Michel",\n todos: [\n {\n title: "Get coffee",\n done: false\n }\n ]\n }\n ]\n ])\n}\n\n// \u6df1\u5ea6\u66f4\u65b0\nconst nextStore = produce(store, draft => {\n draft.users.get("17").todos[0].done = true\n})\n\n// \u8fc7\u6ee4\nconst nextStore = produce(store, draft => {\n const user = draft.users.get("17")\n\n user.todos = user.todos.filter(todo => todo.done)\n})\n')),(0,d.kt)("p",null,"\u8bf7\u6ce8\u610f\uff0c\u8bb8\u591a\u6570\u7ec4\u64cd\u4f5c\u53ef\u7528\u4e8e\u901a\u8fc7\u4f20\u9012\u591a\u4e2a\u53c2\u6570\u6216\u4f7f\u7528\u5c55\u5f00\u64cd\u4f5c\u6765\u4e00\u6b21\u63d2\u5165\u591a\u4e2a\u5143\u7d20\uff1a",(0,d.kt)("inlineCode",{parentName:"p"},"todos.unshift(...items)"),"\u3002"),(0,d.kt)("p",null,"\u8bf7\u6ce8\u610f\uff0c\u5f53\u5904\u7406\u5305\u542b\u901a\u5e38\u7531\u67d0\u4e2a id \u6807\u8bc6\u7684\u5bf9\u8c61\u7684\u6570\u7ec4\u65f6\uff0c\u6211\u4eec\u5efa\u8bae\u4f7f\u7528\u57fa\u4e8e ",(0,d.kt)("inlineCode",{parentName:"p"},"Map")," \u6216\u7d22\u5f15\u7684\u5bf9\u8c61\uff08\u5982\u4e0a\u6240\u793a\uff09\u800c\u4e0d\u662f\u6267\u884c\u9891\u7e41\u7684\u67e5\u627e\u64cd\u4f5c\uff0c\u67e5\u627e\u8868\u901a\u5e38\u6267\u884c\u6548\u7387\u66f4\u9ad8\u3002"))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/zh-CN/assets/js/3ff44509.6b0adc7b.js b/zh-CN/assets/js/3ff44509.6b0adc7b.js new file mode 100644 index 00000000..fd59c102 --- /dev/null +++ b/zh-CN/assets/js/3ff44509.6b0adc7b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkimmer_website=self.webpackChunkimmer_website||[]).push([[366],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>k});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),o=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=o(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,c=m(e,["components","mdxType","originalType","parentName"]),u=o(n),d=a,k=u["".concat(p,".").concat(d)]||u[d]||s[d]||i;return n?r.createElement(k,l(l({ref:t},c),{},{components:n})):r.createElement(k,l({ref:t},c))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=d;var m={};for(var p in t)hasOwnProperty.call(t,p)&&(m[p]=t[p]);m.originalType=e,m[u]="string"==typeof e?e:a,l[1]=m;for(var o=2;o{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>d,frontMatter:()=>m,metadata:()=>o,toc:()=>u});var r=n(3117),a=n(102),i=(n(7294),n(3905)),l=["components"],m={id:"installation",title:"\u5b89\u88c5"},p=void 0,o={unversionedId:"installation",id:"installation",title:"\u5b89\u88c5",description:"<\/script>')),(0,i.kt)("li",{parentName:"ul"},"JSDelivr: ",(0,i.kt)("inlineCode",{parentName:"li"},' + + + + + + + + + + + + +
+

createDraft / finishDraft

egghead.io 第11课: 创建异步 producers(以及为什么不应该这样做)

createDraft and finishDraft

createDraftfinishDraft 是两个底层函数,它们对于在 immer 之上构建抽象的库非常有用。它避免了为了使用 draft 始终创建函数。相反,人们可以创建一个 draft,对其进行修改,并在未来的某个时间完成该 draft,在这种情况下,将产生下一个不可变状态。例如,我们可以将上面的示例重写为:

Beyond that, createDraft / finishDraft could be used to express async updates to drafts:

import {createDraft, finishDraft} from "immer"

const user = {
name: "michel",
todos: []
}

const draft = createDraft(user)
draft.todos = await (await window.fetch("http://host/" + draft.name)).json()
const loadedUser = finishDraft(draft)

注意:finishDraft 以一个 patchListener 作为第二个参数,可以用来记录 patches,类似于 produce

警告:一般情况下,我们建议使用 producer 而不是 createDraft / finishDraft 组合,produce 在使用中不易出错,并且在代码中更清楚地区分了可变性和不变性的概念。

+ + + + \ No newline at end of file diff --git a/zh-CN/built-with/index.html b/zh-CN/built-with/index.html new file mode 100644 index 00000000..181b3b82 --- /dev/null +++ b/zh-CN/built-with/index.html @@ -0,0 +1,26 @@ + + + + + +基于 Immer | Immer + + + + + + + + + + + + + + +
+

基于 Immer

  • react-copy-write 具有可变 API 的不可变状态
  • redux-toolkit 官方的,opinionated,自带全套工具的效率 Redux 开发
  • immer based handleActions Redux 自由动作脚手架
  • redux-box 模块化且易于掌握的基于 redux 的状态管理,样板代码最少
  • quick-redux 使 redux 开发更快更容易的工具
  • bey 使用 Immer 实现 React 的简单不可变状态
  • cool-store CoolStore 是建立在 ImmerJS 和 RxJS 之上的不可变状态存储
  • immer-wieder 结合 React 16 Context 和 immer 用于 Redux 语义的状态管理库
  • robodux 减少 redux 样板的灵活脚手架
  • immer-reducer 用于 React Hooks 和 Redux 的 Typescript 类型安全和简洁的 reducer
  • redux-ts-utils 使用 Redux 创建类型安全的应用程序所需的一切,强调简单性
  • react-state-tree 将您的状态持久化到类似 redux 的状态树,useState 的替代品
  • redux-immer 用于创建与 immer 状态一起使用的 Redux combineReducers 的等效函数。像 redux-immutable 但是 immer的
  • ngrx-wieder 轻量级但可配置的解决方案,用于在 NgRx 和 Immer 之上的 Angular 应用程序中实现撤消重做
  • ... 还有 很多
+ + + + \ No newline at end of file diff --git a/zh-CN/complex-objects/index.html b/zh-CN/complex-objects/index.html new file mode 100644 index 00000000..59685f5f --- /dev/null +++ b/zh-CN/complex-objects/index.html @@ -0,0 +1,26 @@ + + + + + +类 | Immer + + + + + + + + + + + + + + +
+

普通对象(没有原型的对象)、数组、MapSet 总是可以用 Immer 更新。所有其他对象都必须使用 immerable 符号将自己标记为与 Immer 兼容。当这些对象之一在 produce 中进行更改时,它的原型将保留在副本之间

import {immerable} from "immer"

class Foo {
[immerable] = true // 方式一

constructor() {
this[immerable] = true // 方式二
}
}

Foo[immerable] = true // 方式三

例子

import {immerable, produce} from "immer"

class Clock {
[immerable] = true

constructor(hour, minute) {
this.hour = hour
this.minute = minute
}

get time() {
return `${this.hour}:${this.minute}`
}

tick() {
return produce(this, draft => {
draft.minute++
})
}
}

const clock1 = new Clock(12, 10)
const clock2 = clock1.tick()
console.log(clock1.time) // 12:10
console.log(clock2.time) // 12:11
console.log(clock2 instanceof Clock) // true

语义细节

关于类的 draft 对象语义如下:

  1. 类的 draft 是一个新对象,但与原始对象具有相同的原型。
  2. 创建 draft 时,Immer 会将所有拥有的的属性从源对象复制到 draft。这包括不可枚举和符号属性。
  3. 源对象拥有的 getter 将在复制过程中被调用,就像 Object.assign 方法一样
  4. 继承的 getter 和方法将保持原样并被 draft 继承
  5. Immer 不会调用构造函数
  6. 最终实例将使用与创建 draft 相同的机制构建。
  7. 只有具有 setter 的 getter 才能在 draft 中写入,否则无法将值复制回来。

因为 Immer 会将对象拥有的 getter 解引用到普通属性中,所以可以使用在其字段上使用 getter/setter 获得的对象,就像MobX 和 Vue。

Immer 不支持外来/引擎原生对象,例如 DOM 节点或 Buffers,也不支持继承的 Map、Set 或数组,并且不能在它们上使用 immerable 符号。

因此,例如在使用 Date 对象时,您应该始终创建一个新的 Date 实例,而不是改变现有的 Date 对象。

+ + + + \ No newline at end of file diff --git a/zh-CN/current/index.html b/zh-CN/current/index.html new file mode 100644 index 00000000..2a884335 --- /dev/null +++ b/zh-CN/current/index.html @@ -0,0 +1,28 @@ + + + + + +从 draft 中提取当前 state | Immer + + + + + + + + + + + + + + +
+

从 draft 中提取当前 state

Immer 暴露了一个命名导出的 current函数,可以创建 draft 对象当前状态的一个副本。 +这对于调试非常有用(因为这些对象不会是代理对象,也不会被记录下来)。 +此外,对 current 的引用可以安全地从 produce 函数中释放。换句话说,current 提供 draft 当前状态的快照。

current 工作生成的对象类似于 produced 本身创建的对象。

  1. 未修改的对象将在结构上与原始对象共享。
  2. 如果未对 draft 进行任何更改,通常它会保留 original(draft) === current(draft),但这并不能保证。
  3. 未来对 draft 的更改不会反映在 current 生成的对象中(不可被 draft 对象的引用除外)
  4. produce 创建的对象不同,current 创建的对象不会被冻结。

谨慎使用 current,这可能是一项潜在的昂贵操作,尤其是在使用 ES5 时。

请注意,不能在不是 draft 的对象上调用 current

例子

以下示例显示了 current(和 original )的效果:

const base = {
x: 0
}

const next = produce(base, draft => {
draft.x++
const orig = original(draft)
const copy = current(draft)
console.log(orig.x)
console.log(copy.x)

setTimeout(() => {
// 将在 produce 完成后执行
console.log(orig.x)
console.log(copy.x)
}, 100)

draft.x++
console.log(draft.x)
})
console.log(next.x)

// 将会打印
// 0 (orig.x)
// 1 (copy.x)
// 2 (draft.x)
// 2 (next.x)
// 0 (after timeout, orig.x)
// 1 (after timeout, copy.x)
+ + + + \ No newline at end of file diff --git a/zh-CN/curried-produce/index.html b/zh-CN/curried-produce/index.html new file mode 100644 index 00000000..a66e0ee1 --- /dev/null +++ b/zh-CN/curried-produce/index.html @@ -0,0 +1,26 @@ + + + + + +柯里化 producers | Immer + + + + + + + + + + + + + + +
+

柯里化 producers

egghead.io 第六课: 使用柯里化简化代码

将函数作为第一个参数传递给 produce 会创建一个函数,该函数尚未将 produce 应用于特定 state,而是创建一个函数,该函数将应用于将来传递给它的任何 state。这通常称为柯里化。举个例子:

import {produce} from "immer"

function toggleTodo(state, id) {
return produce(state, draft => {
const todo = draft.find(todo => todo.id === id)
todo.done = !todo.done
})
}

const baseState = [
{
id: "JavaScript",
title: "Learn TypeScript",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]

const nextState = toggleTodo(baseState, "Immer")

上面的 toggleTodo 模式非常典型;传递一个现有的 state 来 produce,修改 draft,然后返回结果。由于 state 除了将其传递给 produce 之外没有其他任何用途,因此可以通过使用 produce 的柯里化形式来简化上面的示例,其中您只传递 produce recipe 函数,并且 produce 将返回一个应用 recipe 到基础状态的新函数。这允许我们缩短上述 toggleTodo 定义。

import {produce} from "immer"

// curried producer:
const toggleTodo = produce((draft, id) => {
const todo = draft.find(todo => todo.id === id)
todo.done = !todo.done
})

const baseState = [
/* as is */
]

const nextState = toggleTodo(baseState, "Immer")

请注意,id 参数现在已成为 recipe 函数的一部分!这种拥有 curried producers 的模式与 React 中的 useState Hook 非常巧妙地结合在一起,我们将在下一页看到。

+ + + + \ No newline at end of file diff --git a/zh-CN/docs/404.html/index.html b/zh-CN/docs/404.html/index.html new file mode 100644 index 00000000..dc9bca10 --- /dev/null +++ b/zh-CN/docs/404.html/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/api/index.html b/zh-CN/docs/api/index.html new file mode 100644 index 00000000..4c5dd6cb --- /dev/null +++ b/zh-CN/docs/api/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/async/index.html b/zh-CN/docs/async/index.html new file mode 100644 index 00000000..17233bb5 --- /dev/null +++ b/zh-CN/docs/async/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/built-with/index.html b/zh-CN/docs/built-with/index.html new file mode 100644 index 00000000..e591fb7d --- /dev/null +++ b/zh-CN/docs/built-with/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/complex-objects/index.html b/zh-CN/docs/complex-objects/index.html new file mode 100644 index 00000000..4632060d --- /dev/null +++ b/zh-CN/docs/complex-objects/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/current/index.html b/zh-CN/docs/current/index.html new file mode 100644 index 00000000..5d236008 --- /dev/null +++ b/zh-CN/docs/current/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/curried-produce/index.html b/zh-CN/docs/curried-produce/index.html new file mode 100644 index 00000000..7f0dc43d --- /dev/null +++ b/zh-CN/docs/curried-produce/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/example-setstate/index.html b/zh-CN/docs/example-setstate/index.html new file mode 100644 index 00000000..71e2bfed --- /dev/null +++ b/zh-CN/docs/example-setstate/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/faq/index.html b/zh-CN/docs/faq/index.html new file mode 100644 index 00000000..efaa6a1d --- /dev/null +++ b/zh-CN/docs/faq/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/freezing/index.html b/zh-CN/docs/freezing/index.html new file mode 100644 index 00000000..a3840bcb --- /dev/null +++ b/zh-CN/docs/freezing/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/index.html b/zh-CN/docs/index.html new file mode 100644 index 00000000..8f94224e --- /dev/null +++ b/zh-CN/docs/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/installation/index.html b/zh-CN/docs/installation/index.html new file mode 100644 index 00000000..f16a885a --- /dev/null +++ b/zh-CN/docs/installation/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/map-set/index.html b/zh-CN/docs/map-set/index.html new file mode 100644 index 00000000..8566da0e --- /dev/null +++ b/zh-CN/docs/map-set/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/original/index.html b/zh-CN/docs/original/index.html new file mode 100644 index 00000000..582bd959 --- /dev/null +++ b/zh-CN/docs/original/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/other-lang/index.html b/zh-CN/docs/other-lang/index.html new file mode 100644 index 00000000..9e80f7ad --- /dev/null +++ b/zh-CN/docs/other-lang/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/patches/index.html b/zh-CN/docs/patches/index.html new file mode 100644 index 00000000..0df1366c --- /dev/null +++ b/zh-CN/docs/patches/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/performance/index.html b/zh-CN/docs/performance/index.html new file mode 100644 index 00000000..ec9a4598 --- /dev/null +++ b/zh-CN/docs/performance/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/pitfalls/index.html b/zh-CN/docs/pitfalls/index.html new file mode 100644 index 00000000..07b3a9fc --- /dev/null +++ b/zh-CN/docs/pitfalls/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/produce/index.html b/zh-CN/docs/produce/index.html new file mode 100644 index 00000000..21aecc5d --- /dev/null +++ b/zh-CN/docs/produce/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/resources/index.html b/zh-CN/docs/resources/index.html new file mode 100644 index 00000000..50e17626 --- /dev/null +++ b/zh-CN/docs/resources/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/return/index.html b/zh-CN/docs/return/index.html new file mode 100644 index 00000000..3777d6e4 --- /dev/null +++ b/zh-CN/docs/return/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/support/index.html b/zh-CN/docs/support/index.html new file mode 100644 index 00000000..f70aaa03 --- /dev/null +++ b/zh-CN/docs/support/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/typescript/index.html b/zh-CN/docs/typescript/index.html new file mode 100644 index 00000000..5c99b598 --- /dev/null +++ b/zh-CN/docs/typescript/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/docs/update-patterns/index.html b/zh-CN/docs/update-patterns/index.html new file mode 100644 index 00000000..573f3f4e --- /dev/null +++ b/zh-CN/docs/update-patterns/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/example-setstate/index.html b/zh-CN/example-setstate/index.html new file mode 100644 index 00000000..738b9ef6 --- /dev/null +++ b/zh-CN/example-setstate/index.html @@ -0,0 +1,26 @@ + + + + + +React & Immer | Immer + + + + + + + + + + + + + + +
+

React & Immer

egghead.io 第八课: 使用 Immer 和 useState,或者 useImmer。

useState + Immer

useState hook 假定存储在其中的任何 state 都被视为不可变的。使用 Immer 可以大大简化 React 组件状态的深度更新。下面的例子展示了如何使用 produceuseState ,可以在 CodeSandbox 试试。

import React, { useCallback, useState } from "react";
import {produce} from "immer";

const TodoList = () => {
const [todos, setTodos] = useState([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);

const handleToggle = useCallback((id) => {
setTodos(
produce((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
})
);
}, []);

const handleAdd = useCallback(() => {
setTodos(
produce((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
})
);
}, []);

return (<div>{*/ See CodeSandbox */}</div>)
}

useImmer

由于所有 state 的更新都使用 produce 包装的更新模式,所以我们可以通过将更新模式包装在 use-immer 包中来简化上述操作

import React, { useCallback } from "react";
import { useImmer } from "use-immer";

const TodoList = () => {
const [todos, setTodos] = useImmer([
{
id: "React",
title: "Learn React",
done: true
},
{
id: "Immer",
title: "Try Immer",
done: false
}
]);

const handleToggle = useCallback((id) => {
setTodos((draft) => {
const todo = draft.find((todo) => todo.id === id);
todo.done = !todo.done;
});
}, []);

const handleAdd = useCallback(() => {
setTodos((draft) => {
draft.push({
id: "todo_" + Math.random(),
title: "A new todo",
done: false
});
});
}, []);

// etc

完整的 demo 请参阅 CodeSandbox

useReducer + Immer

useState 类似,useReducer 也与 Immer 巧妙结合,如 CodeSandbox 所示:

import React, {useCallback, useReducer} from "react"
import {produce} from "immer"

const TodoList = () => {
const [todos, dispatch] = useReducer(
produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
}),
[
/* initial todos */
]
)

const handleToggle = useCallback(id => {
dispatch({
type: "toggle",
id
})
}, [])

const handleAdd = useCallback(() => {
dispatch({
type: "add",
id: "todo_" + Math.random()
})
}, [])

// etc
}

useImmerReducer

同上,可以通过 use-immer 包中的 useImmerReducer 简化 (demo)

import React, { useCallback } from "react";
import { useImmerReducer } from "use-immer";

const TodoList = () => {
const [todos, dispatch] = useImmerReducer(
(draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find((todo) => todo.id === action.id);
todo.done = !todo.done;
break;
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
});
break;
default:
break;
}
},
[ /* initial todos */ ]
);

//etc

Redux + Immer

Redux + Immer 在 Redux Toolkit 的文档中被广泛介绍。对于没有 Redux Toolkit 的 Redux,可以应用与上面应用于 useReducer 相同的技巧:使用 produce 包装 reducer 函数,您可以安全地修改 draft!

例子:

import {produce} from "immer"

// 初始 state
const INITIAL_STATE = [
/* 一系列 todos */
]

const todosReducer = produce((draft, action) => {
switch (action.type) {
case "toggle":
const todo = draft.find(todo => todo.id === action.id)
todo.done = !todo.done
break
case "add":
draft.push({
id: action.id,
title: "A new todo",
done: false
})
break
default:
break
}
})
+ + + + \ No newline at end of file diff --git a/zh-CN/faq/index.html b/zh-CN/faq/index.html new file mode 100644 index 00000000..7afcc45f --- /dev/null +++ b/zh-CN/faq/index.html @@ -0,0 +1,26 @@ + + + + + +常见问题 | Immer + + + + + + + + + + + + + + +
+

常见问题

Q: Immer 如何工作

阅读介绍博客的(第二部分)

Q: Immer 是否使用结构共享?这样我的选择器就可以被记住了吗?

A: 是的

Q: Immer 是否支持深度更新?

A: 是的

Q: 我的目标环境中没有代理。我可以使用 Immer 吗?

A: 可以 - 查看细节

Q: 使用 Immer 时可以对我的数据结构进行类型检查吗?

A: 可以

Q: 使用 Immer 时,我可以在状态树中存储 Date 对象、函数等吗?

A: 可以

Q: 我可以使用 Map 和 Sets 吗?

A: 可以

Q: 快吗?

A: 快

Q: 灵感! Immer 可以为我冻结状态吗?

A: 可以

+ + + + \ No newline at end of file diff --git a/zh-CN/freezing/index.html b/zh-CN/freezing/index.html new file mode 100644 index 00000000..541a5e6f --- /dev/null +++ b/zh-CN/freezing/index.html @@ -0,0 +1,26 @@ + + + + + +自动冻结 | Immer + + + + + + + + + + + + + + +
+

自动冻结

egghead.io 第7课: Immer 自动冻结数据

Immer 自动冻结所有使用 produce 修改的任何 state。这可以防止在 producer 之外意外修改 state。在大多数情况下,这是最佳实践,但你可以通过 setAutoFreeze(true / false) 显式打开或关闭此功能。

Immer 永远不会冻结不可枚举、非自己或符号属性的(内容),除非它们的内容是可以被 draft 的。

⚠️ Immer 以递归方式冻结所有内容,对于将来不会更改的大型数据对象,这可能会矫枉过正,在这种情况下,使用 freeze 函数 浅层冻结数据会更有效。⚠️

⚠️ 如果启用了自动冻结,recipe 函数并非完全没有副作用:任何最终出现在 produce 结果中的普通对象或数组都将被冻结,即使这些对象在 producer 开始之前没有被冻结!⚠️

+ + + + \ No newline at end of file diff --git a/zh-CN/img/favicon.ico b/zh-CN/img/favicon.ico new file mode 100644 index 00000000..272e0837 Binary files /dev/null and b/zh-CN/img/favicon.ico differ diff --git a/zh-CN/img/immer-logo.png b/zh-CN/img/immer-logo.png new file mode 100644 index 00000000..9a7221e2 Binary files /dev/null and b/zh-CN/img/immer-logo.png differ diff --git a/zh-CN/img/immer-logo.svg b/zh-CN/img/immer-logo.svg new file mode 100644 index 00000000..da42bc8d --- /dev/null +++ b/zh-CN/img/immer-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/zh-CN/img/immer.png b/zh-CN/img/immer.png new file mode 100644 index 00000000..c83185f8 Binary files /dev/null and b/zh-CN/img/immer.png differ diff --git a/zh-CN/img/performance.png b/zh-CN/img/performance.png new file mode 100644 index 00000000..1fd5c8be Binary files /dev/null and b/zh-CN/img/performance.png differ diff --git a/zh-CN/img/proxy.png b/zh-CN/img/proxy.png new file mode 100644 index 00000000..8a4312e8 Binary files /dev/null and b/zh-CN/img/proxy.png differ diff --git a/zh-CN/img/tree.png b/zh-CN/img/tree.png new file mode 100644 index 00000000..eefa2234 Binary files /dev/null and b/zh-CN/img/tree.png differ diff --git a/zh-CN/index.html b/zh-CN/index.html new file mode 100644 index 00000000..c6360b3b --- /dev/null +++ b/zh-CN/index.html @@ -0,0 +1,26 @@ + + + + + +Immer 入门 | Immer + + + + + + + + + + + + + + +
+

Immer 入门

Immer

2019 年 “年度突破”React 开源奖和“最有影响的贡献”JavaScript 开源奖的获得者


Immer(德语为:always)是一个小型包,可让您以更方便的方式使用不可变状态。

Immer 简化了不可变数据结构的处理

Immer 可以在需要使用不可变数据结构的任何上下文中使用。例如与 React state、React 或 Redux reducers 或者 configuration management 结合使用。不可变的数据结构允许(高效)的变化检测:如果对对象的引用没有改变,那么对象本身也没有改变。此外,它使克隆对象相对便宜:数据树的未更改部分不需要复制,并且在内存中与相同状态的旧版本共享

一般来说,这些好处可以通过确保您永远不会更改对象、数组或映射的任何属性来实现,而是始终创建一个更改后的副本。在实践中,这可能会导致代码编写起来非常麻烦,并且很容易意外违反这些约束。 Immer 将通过解决以下痛点来帮助您遵循不可变数据范式:

  1. Immer 将检测到意外 mutations 并抛出错误。
  2. Immer 将不再需要创建对不可变对象进行深度更新时所需的典型样板代码:如果没有 Immer,则需要在每个级别手动制作对象副本。通常通过使用大量 ... 展开操作。使用 Immer 时,会对 draft 对象进行更改,该对象会记录更改并负责创建必要的副本,而不会影响原始对象。
  3. 使用 Immer 时,您无需学习专用 API 或数据结构即可从范例中受益。使用 Immer,您将使用纯 JavaScript 数据结构,并使用众所周知的安全地可变 JavaScript API。

一个简单的比较示例

const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]

假设我们有上述基本状态,我们需要更新第二个 todo,并添加第三个。但是,我们不想改变原始的 baseState,我们也想避免深度克隆(以保留第一个 todo)

不使用 Immer

如果没有 Immer,我们将不得不小心地浅拷贝每层受我们更改影响的 state 结构

const nextState = baseState.slice() // 浅拷贝数组
nextState[1] = {
// 替换第一层元素
...nextState[1], // 浅拷贝第一层元素
done: true // 期望的更新
}
// 因为 nextState 是新拷贝的, 所以使用 push 方法是安全的,
// 但是在未来的任意时间做相同的事情会违反不变性原则并且导致 bug!
nextState.push({title: "Tweet about it"})

使用 Immer

使用 Immer,这个过程更加简单。我们可以利用 produce 函数,它将我们要更改的 state 作为第一个参数,对于第二个参数,我们传递一个名为 recipe 的函数,该函数传递一个 draft 参数,我们可以对其应用直接的 mutations。一旦 recipe 执行完成,这些 mutations 被记录并用于产生下一个状态。 produce 将负责所有必要的复制,并通过冻结数据来防止未来的意外修改。

import {produce} from "immer"

const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})

正在寻找结合 React 的 Immer?跳到 React + Immer 页面

Immer 如何工作

基本思想是,使用 Immer,您会将所有更改应用到临时 draft,它是 currentState 的代理。一旦你完成了所有的 mutations,Immer 将根据对 draft statemutations 生成 nextState。这意味着您可以通过简单地修改数据来与数据交互,同时保留不可变数据的所有好处。

immer-hd.png

使用 Immer 就像拥有一个私人助理。助手拿一封信(当前状态)并给您一份副本(草稿)以记录更改。完成后,助手将接受您的草稿并为您生成真正不变的最终字母(下一个状态)。

前往 下一章节 以进一步深入了解 produce

好处

  • 遵循不可变数据范式,同时使用普通的 JavaScript 对象、数组、Sets 和 Maps。无需学习新的 API 或 "mutations patterns"!
  • 强类型,无基于字符串的路径选择器等
  • 开箱即用的结构共享
  • 开箱即用的对象冻结
  • 深度更新轻而易举
  • 样板代码减少。更少的噪音,更简洁的代码
  • 对 JSON 补丁的一流支持
  • 小:3KB gzip
+ + + + \ No newline at end of file diff --git a/zh-CN/installation/index.html b/zh-CN/installation/index.html new file mode 100644 index 00000000..19cc5672 --- /dev/null +++ b/zh-CN/installation/index.html @@ -0,0 +1,26 @@ + + + + + +安装 | Immer + + + + + + + + + + + + + + +
+

安装

Immer 可以作为直接依赖项安装,并且可以在任何 ES5 环境中工作:

  • Yarn: yarn add immer
  • NPM: npm install immer
  • CDN: 暴露的全局变量是 immer
    • Unpkg: <script src="https://unpkg.com/immer"></script>
    • JSDelivr: <script src="https://cdn.jsdelivr.net/npm/immer"></script>
    • ⚠️ 使用 CDN 时,最好检查浏览器中的 url 并查看它解析为哪个版本,这样当更新发布时,您的用户不会意外地获得更新的版本。因此,请改用如下网址:https://unpkg.com/immer@6.0.3/dist/immer.umd.production.min.js 。在 URL 中将 production.min 替换为 development 以进行开发构建。

选择您的 Immer 版本

本节仅适用于版本 6 及更高版本

为确保 Immer 尽可能小,并非每个项目都需要的功能已选择加入,并且必须明确启用。这可确保在将您的应用程序捆绑用于生产时,未使用的功能不会占用任何空间。

可以选择加入以下功能:

功能描述调用方法
ES 5 支持如果您的应用程序需要能够在较旧的 JavaScript 环境(例如 Internet Explorer 或 React Native)上运行,请启用此功能。enableES5()
ES2015 Map and Set 支持要使 Immer 能够对原生 Map 和 Set 集合进行操作,请启用此功能enableMapSet()
JSON 补丁 支持Immer 可以跟踪您对 draft 对象所做的所有更改。这对于使用 JSON 补丁时传达更改很有用enablePatches()

例如,如果您想在 Map 上使用 produce ,则需要在应用程序启动期间启用此功能一次:

// 在你的应用程序入口文件
import {enableMapSet} from "immer"

enableMapSet()

// ...然后
import {produce} from "immer"

const usersById_v1 = new Map([
["michel", {name: "Michel Weststrate", country: "NL"}]
])

const usersById_v2 = produce(usersById_v1, draft => {
draft.get("michel").country = "UK"
})

expect(usersById_v1.get("michel").country).toBe("NL")
expect(usersById_v2.get("michel").country).toBe("UK")

Immer 以大约 3KB 的 gzip 压缩开始。每个启用的插件都会增加 < 1 KB。细分如下

Import size report for immer:
┌───────────────────────┬───────────┬────────────┬───────────┐
│ (index) │ just this │ cumulative │ increment │
├───────────────────────┼───────────┼────────────┼───────────┤
│ import * from 'immer' │ 5033 │ 0 │ 0 │
│ produce │ 3324 │ 3324 │ 0 │
│ enableMapSet │ 4030 │ 4039 │ 715 │
│ enablePatches │ 4112 │ 4826 │ 787 │
└───────────────────────┴───────────┴────────────┴───────────┘
(this report was generated by npmjs.com/package/import-size)

Immer 使用在旧的 JavaScript 环境?

默认情况下,produce 尝试使用代理以获得最佳性能。但是,在较旧的 JavaScript 引擎上,代理不可用。例如,在 Android 上运行 Microsoft Internet Explorer 或 React Native(如果 React Native < v0.59 或在 React Native < v0.64 上使用 Hermes 引擎)时。在这种情况下,Immer 将回退到与 ES5 兼容的实现,其工作方式相同,但速度稍慢

  • 从版本 6 开始,必须通过调用 enableES5() 显式启用对回退实现的支持
  • Version 10 drops the fallback implementation fully, and cannot be used in browsers / engines that don't support Proxy.
+ + + + \ No newline at end of file diff --git a/zh-CN/map-set/index.html b/zh-CN/map-set/index.html new file mode 100644 index 00000000..2ede37b4 --- /dev/null +++ b/zh-CN/map-set/index.html @@ -0,0 +1,26 @@ + + + + + +Map 和 Set | Immer + + + + + + + + + + + + + + +
+

Map 和 Set

⚠ 从版本6开始,对 MapSet 的支持必须在启动应用程序时通过显式调用 enableMapSet()来开启

普通对象、数组、MapSet 总是可以用 Immer 更新。一个使用 Map 和 Immer 的示例:

test("Producers can update Maps", () => {
const usersById_v1 = new Map()

const usersById_v2 = produce(usersById_v1, draft => {
// 修改 map 会生成一个新的 map
draft.set("michel", {name: "Michel Weststrate", country: "NL"})
})

const usersById_v3 = produce(usersById_v2, draft => {
// 在 map 深处进行修改,同样会生成一个新的 map!
draft.get("michel").country = "UK"
})

// 我们每次都会得到一个新的 map
expect(usersById_v2).not.toBe(usersById_v1)
expect(usersById_v3).not.toBe(usersById_v2)
// 显然它们的内容不同
expect(usersById_v1).toMatchInlineSnapshot(`Map {}`)
expect(usersById_v2).toMatchInlineSnapshot(`
Map {
"michel" => Object {
"country": "NL",
"name": "Michel Weststrate",
},
}
`)
expect(usersById_v3).toMatchInlineSnapshot(`
Map {
"michel" => Object {
"country": "UK",
"name": "Michel Weststrate",
},
}
`)
// 旧的从来不会被更改
expect(usersById_v1.size).toBe(0)
// 试图在 produce 之外修改 map 对象是不行的!
expect(() => usersById_v3.clear()).toThrowErrorMatchingInlineSnapshot(
`"This object has been frozen and should not be mutated"`
)
})

Immer 生成的 Map 和 Set 将被人为地设置为不可变。这意味着在 produce 之外尝试 setclear等可变方法时,它们将抛出异常。

注意:map 的永远不会被更改!这样做是为了避免混淆语义并保持键始终引用相等

+ + + + \ No newline at end of file diff --git a/zh-CN/original/index.html b/zh-CN/original/index.html new file mode 100644 index 00000000..c6db885a --- /dev/null +++ b/zh-CN/original/index.html @@ -0,0 +1,27 @@ + + + + + +从 draft 中提取原始 state | Immer + + + + + + + + + + + + + + +
+

从 draft 中提取原始 state

Immer中暴露了一个命名对象 original,将从 produce 内部的代理实例获取原始对象(对于未代理值返回 undefined。 +一个好的例子是:当在一个树状 state 中使用严格相等搜索结点的时候它很有用。

import {original, produce} from "immer"

const baseState = {users: [{name: "Richie"}]}
const nextState = produce(baseState, draftState => {
original(draftState.users) // is === baseState.users
})

只是想知道一个值是否是代理实例?使用 isDraft 函数!请注意,不能在不是 draft 的对象上调用 original

import {isDraft, produce} from "immer"

const baseState = {users: [{name: "Bobby"}]}
const nextState = produce(baseState, draft => {
isDraft(draft) // => true
isDraft(draft.users) // => true
isDraft(draft.users[0]) // => true
})
isDraft(nextState) // => false
+ + + + \ No newline at end of file diff --git a/zh-CN/other-lang/index.html b/zh-CN/other-lang/index.html new file mode 100644 index 00000000..d69c97fd --- /dev/null +++ b/zh-CN/other-lang/index.html @@ -0,0 +1,26 @@ + + + + + +移植到其它语言 | Immer + + + + + + + + + + + + + + +
+

移植到其它语言

Immer 已经被移植到其它编程语言。

编程语言链接
JavaJimmer
+ + + + \ No newline at end of file diff --git a/zh-CN/patches/index.html b/zh-CN/patches/index.html new file mode 100644 index 00000000..35f915fe --- /dev/null +++ b/zh-CN/patches/index.html @@ -0,0 +1,26 @@ + + + + + +Patches | Immer + + + + + + + + + + + + + + +
+

Patches

egghead.io 第14课: 使用 produceWithPatches 捕获 Patches
egghead.io 第16课: 使用 applyPatches 应用 Patches

⚠ 在版本 6 之后,必须在启动应用程序调用一次 enablePatches() 来启用对 Patches 的支持。

在 producer 运行期间,Immer 可以记录所有的补丁来回溯 reducer 造成的更改 。这是一个非常强大的工具,如果您想暂时 fork 您的状态并回溯对原始状态的更改。

Patches 在下面场景很有用:

  • 与其他方交换增量更新,例如通过
  • 对于调试/跟踪,准确查看状态如何随时间变化
  • 作为撤消/重做的基础或作为在稍微不同的状态树上回溯更改的方法。

为了帮助回溯补丁,applyPatches 派上用场了。这是一个如何使用 Patches 来记录增量更新并(反向)应用它们的示例:

import {produce, applyPatches} from "immer"

// 版本 6
import {enablePatches} from "immer"
enablePatches()

let state = {
name: "Micheal",
age: 32
}

// 假设用户在向导中
// 他的更改 应该以最终是否为基本状态结束...

let fork = state
// 用户在向导中所作的所有更改
let changes = []
// 与向导中所做的所有更改相反
let inverseChanges = []

fork = produce(
fork,
draft => {
draft.age = 33
},
// 产生的第三个参数是一个回调,patches 将从这里产生
(patches, inversePatches) => {
changes.push(...patches)
inverseChanges.push(...inversePatches)
}
)

// 同时,我们的原始状态被替换,例如
// 从服务器收到了一些更改
state = produce(state, draft => {
draft.name = "Michel"
})

// 当向导完成(成功)后,我们可以将 fork 中的更改重播到新的状态!
state = applyPatches(state, changes)

// state 现在包含来自两个代码路径的更改!
expect(state).toEqual({
name: "Michel", // 服务器更改
age: 33 // 向导更改
})

// 最后,即使在完成向导之后,用户也可能会改变主意并撤消他的更改......
state = applyPatches(state, inverseChanges)
expect(state).toEqual({
name: "Michel", // 没有还原
age: 32 // 还原了
})

生成的 patches 与 RFC-6902 JSON patch standard 类似(但并不相同),除了 path 属性是一个数组,而不是一个字符串。这使得处理 patches 更加容易。如果你想规范化到官方格式,patch.path = patch.path.join("/")应该可以解决这个问题。无论如何,下面就是一堆 patches 和它们回溯的样子。

[
{
"op": "replace",
"path": ["profile"],
"value": {"name": "Veria", "age": 5}
},
{"op": "remove", "path": ["tags", 3]}
]
[
{"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},
{"op": "add", "path": ["tags", 3], "value": "kiddo"}
]

⚠ 注意: Immer 生成的补丁集应该是正确的,也就是说,将它们应用于相同的基础对象应该会导致相同的最终状态。然而,Immer 不保证生成的补丁集是最优的,即可能的最小补丁集。它通常取决于被认为是“最佳”的用例,并且生成最佳补丁集在计算上可能非常昂贵。因此,在某些情况下,您可能想要对生成的补丁进行后处理,或者按照下面的说明压缩它们。

produceWithPatches

egghead.io 第19课: 使用回溯 patches 构建撤销功能
egghead.io 第20课: 使用 patches 构建重做功能

除了设置 patch 监听器之外,获取 patches 的更简单方法是使用 produceWithPatches,它与 produce 具有相同的签名,不过它不止返回 next state,而是一个包含 [nextState, patches, inversePatches] 的元组,和 produce 一样,produceWithPatches 也支持柯里化。

import {produceWithPatches} from "immer"

const [nextState, patches, inversePatches] = produceWithPatches(
{
age: 33
},
draft => {
draft.age++
}
)

将返回:

;[
{
age: 34
},
[
{
op: "replace",
path: ["age"],
value: 34
}
],
[
{
op: "replace",
path: ["age"],
value: 33
}
]
]

有关更深入的研究,请参阅使用 Distributing patches and rebasing actions using Immer

提示:使用此技巧可以 compress patches

+ + + + \ No newline at end of file diff --git a/zh-CN/performance/index.html b/zh-CN/performance/index.html new file mode 100644 index 00000000..c5787e21 --- /dev/null +++ b/zh-CN/performance/index.html @@ -0,0 +1,26 @@ + + + + + +Immer 性能 | Immer + + + + + + + + + + + + + + +
+

Immer 性能

egghead.io 第5课: 在 React 中利用 Immer 的结构共享
egghead.io 第7课: 如果没有语义变化,Immer 会使用原先的数据

这是一个关于 Immer 性能的 简单 benchmark 。该测试需要 50,000 个待办事项并更新其中的 5,000 个。 Freeze 表示状态树在生成后已被冻结。这是一种开发最佳实践,因为它可以防止开发人员意外修改状态树。

上面的数字没有反映一些东西,但实际上,Immer 有时比手写的 reducer 得多。这样做的原因是,Immer 会检测“无操作”状态变化,如果实际上没有任何变化,则返回原始状态,这可以避免很多重新渲染。众所周知,只需应用 immer 即可解决关键性能问题。

这些测试在 Node 10.16.3 上执行。使用 yarn test:perf 在本地重现它们。

performance.png

最重要的结论:

  • Immer with proxies 大约比手写 reducer 慢 2 到 3 倍(上面的测试用例是最坏的情况,请参阅 yarn test:perf 了解更多测试情况)。这在实践中可以忽略不计。
  • Immer 的速度大致与 ImmutableJS 一样快。但是,immutableJS + toJS 明确了后期往往需要付出的代价;将 immutableJS 对象转换回普通对象,以便将它们传递给组件或者进行序列化操作在网络中传输......(还有将从服务器接收到的数据转换为不可变 JS 的前期成本)
  • 生成 patches 不会显著减慢 immer
  • ES5 后备实现的速度大约比代理实现慢两倍,在某些情况下更糟。

性能提示

预冻结数据

当向 Immer producer 中的状态树添加大型数据集时(例如从 JSON 端点接收的数据),可以在首先添加的数据的根上调用 freeze(json) ,来浅冻结它。这将允许 Immer 更快地将新数据添加到树中,因为它将避免递归扫描和冻结新数据的需要。

您可以随时选择退出

immer 在任何地方都是可选的,因此手动编写性能非常苛刻的 reducers ,并将 immer 用于所有普通的的 reducers 是非常好的。即使在 producer 内部,您也可以通过使用 originalcurrent 函数来选择退出 Immer 的某些部分逻辑,并对纯 JavaScript 对象执行一些操作。

对于昂贵的搜索操作,从原始 state 读取,而不是 draft

Immer 会将您在 draft 中读取的任何内容也递归地转换为 draft。如果您对涉及大量读取操作的 draft 进行昂贵的无副作用操作,例如在非常大的数组中使用 find(Index) 查找索引,您可以通过首先进行搜索,并且只在知道索引后调用 produce 来加快速度。这样可以阻止 Immer 将在 draft 中搜索到的所有内容都进行转换。或者,使用 original(someDraft) 对 draft 的原始值执行搜索,这归结为同样的事情。

将 produce 拉到尽可能远的地方

始终尝试将 produce “向上”拉动,例如 for (let x of y) produce(base, d => d.push(x))produce(base, d => { for (let x of y) ) d.push(x)}) 慢得多

+ + + + \ No newline at end of file diff --git a/zh-CN/pitfalls/index.html b/zh-CN/pitfalls/index.html new file mode 100644 index 00000000..bbe0169f --- /dev/null +++ b/zh-CN/pitfalls/index.html @@ -0,0 +1,26 @@ + + + + + +陷阱 | Immer + + + + + + + + + + + + + + +
+

陷阱

性能提示

对于性能提示,阅读 性能提示.

不要重新分配 recipe 参数

永远不要重新分配 draft 参数(例如:draft = myCoolNewState)。相反,要么修改 draft,要么返回新状态。请参阅从 producers 返回数据

Immer 只支持单向树

Immer 假设您的状态是单向树。也就是说,任何对象都不应该在树中出现两次,也不应该有循环引用。从根到树的任何节点应该只有一条路径。

永远不要从 producer 那里显式返回 undefined

可以从 producers 返回值,但不能以这种方式返回 undefined,因为它与根本不更新 draft 没有区别!如果你想用 undefined 替换 draft,只需从 producer 那里返回 nothing

不要修改特殊对象

Immer 不支持特殊对象 比如 window.location.

类应该是可 draft 的或不可变的

您将需要使自己的类能与 Immer 一起正常工作。有关该主题的文档,请查看有关使用复杂对象的部分。

只有有效的索引和长度可以在数组上改变

对于数组,只能改变数值属性和 length 属性。自定义属性不会保留在数组上。

只有来自 state 的数据会被 draft

请注意,来自闭包而不是来自基本 state 的数据将永远不会被 draft,即使数据已成为新 darft 的一部分。

function onReceiveTodo(todo) {
const nextTodos = produce(todos, draft => {
draft.todos[todo.id] = todo
// 注意,因为 todo 来自外部,而不是 draft,所以他不会被 draft,
// 所以下面的修改会影响原来的 todo!
draft.todos[todo.id].done = true

// 上面的代码相当于
todo.done = true
draft.todos[todo.id] = todo
})
}

Immer patches 不一定是最优的

Immer 生成的 patches 应该是正确的,也就是说,将它们应用于相同的基础对象应该会导致相同的最终状态。然而,Immer 不保证生成的 patches 是最优的,即可能的最小 patches

始终使用嵌套 producers 的结果

支持嵌套调用 produce ,但请注意 produce始终产生新状态,因此即使将 draft 传递给嵌套 produce,内部 produce 所做的更改也不会在传递给它的 draft 中可见,只会反映在产生的输出中。换句话说,当使用嵌套 produce 时,您会得到 draft 的 draft,并且内部 produce 的结果应该合并回原始 draft(或返回)。例如,如果内部 produce 的输出没有被使用的话, produce(state, draft => {produce(draft.user, userDraft => { userDraft.name += "!" })}) 将不会生效。使用嵌套 producers 的正确方法是:

produce(state, draft => {
draft.user = produce(draft.user, userDraft => {
userDraft.name += "!"
})
})

Drafts 在引用上不相等

Immer 中的 draft 对象包装在 Proxy 中,因此您不能使用 ===== 来测试原始对象与其 draft 之间的相等性(例如,当匹配数组中的特定元素时)。相反,您可以使用 original 助手:

const remove = produce((list, element) => {
const index = list.indexOf(element) // 不会工作!
const index = original(list).indexOf(element) // 用这个!
if (index > -1) list.splice(index, 1)
})

const values = [a, b, c]
remove(values, a)

如果可以的话,建议在 produce 函数之外执行比较,或者使用 .id 之类的唯一标识符属性,以避免需要使用 original

+ + + + \ No newline at end of file diff --git a/zh-CN/produce/index.html b/zh-CN/produce/index.html new file mode 100644 index 00000000..615b3296 --- /dev/null +++ b/zh-CN/produce/index.html @@ -0,0 +1,26 @@ + + + + + +使用 produce | Immer + + + + + + + + + + + + + + +
+

使用 produce

egghead.io 第 3 课:使用 produce 简化深度更新

Immer 包暴露了一个完成所有工作的默认函数。

produce(currentState, recipe: (draftState) => void): nextState

produce 需要一个 baseState,以及一个可用于对传入的 draft 进行所有所需更改的 recipe。关于 Immer 的有趣之处在于 baseState 将保持不变,但 nextState 将反映对 DraftState 所做的所有更改.

recipe 中,所有标准的 JavaScript API 都可以在 draft 对象上使用,包括属性字段分配、删除操作和修改数组、Map 和 Set 操作,如 push、pop、splice、set、sort、remove 等。

这些 mutations 中的任何一个都不必发生在初始对象上,但它可以修改 draft 深处的任何内容:draft.todos[0].tags["urgent"].author.age = 56

请注意,recipe 函数通常不会返回任何内容。但是,如果您想用另一个对象完全替换 draft,则可以返回,有关更多详细信息,请参阅返回新数据

例子

import {produce} from "immer"

const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]

const nextState = produce(baseState, draftState => {
draftState.push({title: "Tweet about it"})
draftState[1].done = true
})
// 新的 item 仅仅被添加到了 next state
// base state 没有被修改
expect(baseState.length).toBe(2)
expect(nextState.length).toBe(3)

// 同上
expect(baseState[1].done).toBe(false)
expect(nextState[1].done).toBe(true)

// 未修改的数据结构共享
expect(nextState[0]).toBe(baseState[0])
// 改变的数据不是
expect(nextState[1]).not.toBe(baseState[1])

术语

  • (base)state, 传递给 produce 的不可变状态
  • recipe: produce 的第二个参数,它捕获了 base state 应该如何 mutated
  • draft: 任何 recipe 的第一个参数,它是可以安全 mutate 的原始状态的代理。
  • producer. 一个使用 produce 的函数,通常形式为 (baseState, ...arguments) => resultState

请注意,命名 recipe 的第一个参数 draft 并不是绝对必要的。您可以将其命名为任何您想要的名称,例如 user。使用 draft 作为名称只是一个约定,以表明:“这里的 mutation 是可以的”。

+ + + + \ No newline at end of file diff --git a/zh-CN/resources/index.html b/zh-CN/resources/index.html new file mode 100644 index 00000000..e67469df --- /dev/null +++ b/zh-CN/resources/index.html @@ -0,0 +1,26 @@ + + + + + +外部资源 | Immer + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zh-CN/return/index.html b/zh-CN/return/index.html new file mode 100644 index 00000000..15f75cb3 --- /dev/null +++ b/zh-CN/return/index.html @@ -0,0 +1,26 @@ + + + + + +从 producers 返回新数据 | Immer + + + + + + + + + + + + + + +
+

从 producers 返回新数据

egghead.io 第9课: 返回全新 state

不需要从 producer 那里返回任何东西,因为 Immer 无论如何都会返回 draft 的(最终)版本。但是,也允许仅仅 return draft

也允许从 producer 函数中任意返回其他数据。但前提是你没有修改 draft。这对于产生一个全新的 state 很有用。一些例子:

const userReducer = produce((draft, action) => {
switch (action.type) {
case "renameUser":
//可以: 我们修改了当前的 state
draft.users[action.payload.id].name = action.payload.name
return draft // 与仅仅 'return' 相同
case "loadUsers":
// 可以: 我们返回了一个全新的 state
return action.payload
case "adduser-1":
// 不行: 这不会改变 draft ,也不会返回新的状态
// 它不会修改 draft(它只是重新声明它)
// 事实上,这根本没有做任何事情
draft = {users: [...draft.users, action.payload]}
return
case "adduser-2":
// 不行: 修改 draft 的同时返回了一个新的状态
draft.userCount += 1
return {users: [...draft.users, action.payload]}
case "adduser-3":
// 可以: 返回一个新的状态。但是,不必要的复杂和昂贵
return {
userCount: draft.userCount + 1,
users: [...draft.users, action.payload]
}
case "adduser-4":
// 可以: immer 的方式
draft.userCount += 1
draft.users.push(action.payload)
return
}
})

注意:无法以这种方式返回 undefined ,因为它与不更新 draft 没有区别!继续阅读......

使用 nothing 产生 undefined

因此,一般来说,可以通过从 producer 返回一个新值来替换当前 state,而不是修改 draft。然而,有一个微妙的边缘情况:如果您尝试编写一个想要用 undefined 替换当前状态的 producer:

produce({}, draft => {
// 什么也不干
})

或者:

produce({}, draft => {
// 尝试从 producer 中返回 undefined
return undefined
})

问题在于,在 JavaScript 中,一个不返回任何内容的函数也会返回 undefined!所以 immer 无法区分这些不同的情况。因此,默认情况下,Immer 会假设任何返回 undefined 的 producer 只是试图修改 draft。

但是,为了让 Immer 清楚您有意生成 undefined 值,您可以返回内置标记 nothing

import {produce, nothing} from "immer"

const state = {
hello: "world"
}

produce(state, draft => {})
produce(state, draft => undefined)
// 都会返回最初的状态: { hello: "world"}

produce(state, draft => nothing)
// 产生一个新的状态, 'undefined'

注:请注意,此问题特定于 undefined 值,任何其他值(包括 null)都不会受到此问题的影响

提示:为了能够在使用 TypeScript 时从 recipe 中返回 nothingstate 的类型必须接受 undefined 值。

使用 void 的内联快捷方式

egghead.io 第10课: 使用 _void_ 避免意外的返回

Immer 中的 draft 修改通常需要一段代码块,因为返回表示覆盖。有时候你可能觉得这么多的样板代码很糟心。

在这种情况下,您可以使用 javascripts void 运算符,它计算表达式并返回 undefined

// 单次修改
produce(draft => void (draft.user.age += 1))

// 多次修改
produce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))

代码风格是高度个人化的,但对于要被许多人理解的代码库,我们建议坚持经典的 draft => { draft.user.age += 1} 以避免认知开销。

+ + + + \ No newline at end of file diff --git a/zh-CN/support/index.html b/zh-CN/support/index.html new file mode 100644 index 00000000..184c8cd1 --- /dev/null +++ b/zh-CN/support/index.html @@ -0,0 +1,26 @@ + + + + + +赞助 immer | Immer + + + + + + + + + + + + + + +
+

赞助 immer

Immer 目前在 GitHub 上有 350000 个项目依赖于它,每月的下载量接近 10000000 次。然而,只有一开始两天的开发得到了赞助(由 Mendix),之后的所有开发和维护都是用爱发电。

如果您喜欢 Immer,并且对这个包心存感激,或者想确保它的使用寿命,请考虑在 https://opencollective.com/immer 上赞助或使用 PayPal 进行一次性捐赠。

+ + + + \ No newline at end of file diff --git a/zh-CN/typescript/index.html b/zh-CN/typescript/index.html new file mode 100644 index 00000000..3106e6d6 --- /dev/null +++ b/zh-CN/typescript/index.html @@ -0,0 +1,26 @@ + + + + + +Using TypeScript or Flow | Immer + + + + + + + + + + + + + + +
+

Using TypeScript or Flow

egghead.io 第12课: Immer + TypeScript

Immer 包附带了类型定义,TypeScript 和 Flow 开箱即可获取这些定义,无需进一步配置

TypeScript 类型会自动从 draft 类型中删除 readonly 修饰符,并返回与原始类型匹配的值。看这个实际的例子:

import {produce} from "immer"

interface State {
readonly x: number
}

// `x` 不能被修改
const state: State = {
x: 0
}

const newState = produce(state, draft => {
// `x` 可以被修改
draft.x++
})

// `newState.x` 不能在这里被修改

这确保了您可以修改状态的唯一位置是在您的 produce 回调中。它甚至可以递归地和 ReadonlyArray 一起工作。

最佳实践

  1. 始终尽可能将您的 state 定义为只读。这最好地反映了心智模型和现实,因为 Immer 将冻结其所有返回值。
  2. 您可以使用实用类型 Immutable 递归地使整个类型树成为只读的,例如:type ReadonlyState = Immutable<State>
  3. 如果输入状态的原始类型不是不可变的,则 Immer 不会自动将所有返回的类型包装在 Immutable 中。这是为了确保它不会破坏不使用不可变类型的代码库。

柯里化 producers 的提示

我们尝试尽可能多地推断。因此,如果创建了一个柯里化 producer 并直接传递给另一个函数,我们可以从那里推断出类型。这适用于例如 React:

import {Immutable, produce} from "immer"

type Todo = Immutable<{
title: string
done: boolean
}>

// 然后...

const [todo, setTodo] = useState<Todo>({
title: "test",
done: true
})

// 然后...

setTodo(
produce(draft => {
// draft 将是强类型和可变的!
draft.done = !draft.done
})
)

当柯里化 producers 没有直接传递到其他地方时,Immer 可以从 draft 参数推断状态类型。例如在执行以下操作时:

// 请参阅下文以获得更好的解决方案

const toggler = produce((draft: Draft<Todo>) => {
draft.done = !draft.done
})

// typeof toggler = (state: Immutable<Todo>) => Writable<Todo>

请注意,我们确实用 Draft 包装了 draft 参数的 Todo 类型,因为 Todo 是只读类型。对于非只读类型,这不是必需的

对于返回的柯里化函数 toggler,我们将输入类型缩小为 Immutable<Todo>,这样即使 Todo 是可变类型,我们仍将接受不可变的 todo 作为切换器的输入参数。

与之相反,Immer 会将柯里化函数的输出类型扩展Writable<Todo>,以确保它的输出状态也可分配给未明确键入为不可变的变量。

这种类型的缩小/扩大行为可能不受欢迎,甚至可能因为它会导致类型非常多的噪音。因此,我们建议为柯里化 produces 指定 state 泛型 ,以防它无法直接推断,例如上面的 toggler。通过这样做,将跳过自动输出扩大/输入缩小。然而,draft 参数本身仍将被推断为可写 Draft<Todo>

const toggler = produce<Todo>(draft => {
draft.done = !draft.done
})

// typeof toggler = (state: Todo) => Todo

但是,如果柯里化 producer 定义了初始状态,Immer 可以从初始状态推断状态类型,因此在这种情况下也不需要指定泛型:

const state0: Todo = {
title: "test",
done: false
}

// 不需要类型注释,因为我们可以从 state0 推断。
const toggler = produce(draft => {
draft.done = !draft.done
}, state0)

// typeof toggler = (state: Todo) => Todo

如果 toggler 没有初始状态,并且它有柯里化参数,并且您显式设置 state 泛型,则任何附加参数的类型也应显式定义为元组类型:

const toggler = produce<Todo, [boolean]>((draft, newState) => {
draft.done = newState
})

// typeof toggler = (state: Todo, newState: boolean) => Todo

类型转换

produce 内部和外部的类型在概念上可以相同,但从实际角度来看是不同的。例如,上面示例中的 State 应被视为在 produce 外部不可变,但在 produce 内部是可变的。

有时这会导致实际冲突。举个例子:

type Todo = {readonly done: boolean}

type State = {
readonly finishedTodos: readonly Todo[]
readonly unfinishedTodos: readonly Todo[]
}

function markAllFinished(state: State) {
produce(state, draft => {
draft.finishedTodos = state.unfinishedTodos
})
}

这将产生错误:

The type 'readonly Todo[]' is 'readonly' and cannot be assigned to the mutable type '{ done: boolean; }[]'

这个错误的原因是我们将只读的、不可变的数组分配给我们的 draft,draft 需要一个可变的类型,并带有 .push 等方法。就 TS 而言,这些并没有从我们的原始 State 中暴露出来。为了提示 TypeScript 我们希望将此处的集合向上转换为可变数组以用于 draft,我们可以使用函数 castDraft

draft.finishedTodos = castDraft(state.unfinishedTodos) 将使错误消失。

还有函数 castImmutable,以防您需要实现相反的效果。请注意,这些函数出于所有实际目的都是无操作的,它们只会返回其原始值。

提示:您可以将 castImmutableproduce 结合起来,将 produce 的返回类型定义为不可变的内容,即使原始 state 是可变的

// 一个可变数据结构
const baseState = {
todos: [{
done: false
}]
}

const nextState = castImmutable(produce(baseState, _draft => {}))

// nextState 的推断类型现在是:
{
readonly todos: ReadonlyArray<{
readonly done: boolean
}>
})

兼容性

注意: Immer v5.3+ 仅支持 TypeScript v3.7+

注意: Immer v3.0+ 仅支持 TypeScript v3.4+

注意: Immer v1.9+ 仅支持 TypeScript v3.1+

注意: 在未来的版本中可能会删除 flow 支持,我们建议使用 TypeScript

+ + + + \ No newline at end of file diff --git a/zh-CN/update-patterns/index.html b/zh-CN/update-patterns/index.html new file mode 100644 index 00000000..1001db47 --- /dev/null +++ b/zh-CN/update-patterns/index.html @@ -0,0 +1,26 @@ + + + + + +更新模式 | Immer + + + + + + + + + + + + + + +
+

更新模式

在 Immer 之前,使用不可变数据意味着学习所有不可变的更新模式。

为了帮助“忘记”这些模式,这里概述了如何利用内置 JavaScript API 来更新对象和集合

更新对象

import {produce} from "immer"

const todosObj = {
id1: {done: false, body: "Take out the trash"},
id2: {done: false, body: "Check Email"}
}

// 添加
const addedTodosObj = produce(todosObj, draft => {
draft["id3"] = {done: false, body: "Buy bananas"}
})

// 删除
const deletedTodosObj = produce(todosObj, draft => {
delete draft["id1"]
})

// 更新
const updatedTodosObj = produce(todosObj, draft => {
draft["id1"].done = true
})

更新数组

import {produce} from "immer"

const todosArray = [
{id: "id1", done: false, body: "Take out the trash"},
{id: "id2", done: false, body: "Check Email"}
]

// 添加
const addedTodosArray = produce(todosArray, draft => {
draft.push({id: "id3", done: false, body: "Buy bananas"})
})

// 索引删除
const deletedTodosArray = produce(todosArray, draft => {
draft.splice(3 /*索引 */, 1)
})

// 索引更新
const updatedTodosArray = produce(todosArray, draft => {
draft[3].done = true
})

// 索引插入
const updatedTodosArray = produce(todosArray, draft => {
draft.splice(3, 0, {id: "id3", done: false, body: "Buy bananas"})
})

// 删除最后一个元素
const updatedTodosArray = produce(todosArray, draft => {
draft.pop()
})

// 删除第一个元素
const updatedTodosArray = produce(todosArray, draft => {
draft.shift()
})

// 数组开头添加元素
const addedTodosArray = produce(todosArray, draft => {
draft.unshift({id: "id3", done: false, body: "Buy bananas"})
})

// 根据 id 删除
const deletedTodosArray = produce(todosArray, draft => {
const index = draft.findIndex(todo => todo.id === "id1")
if (index !== -1) draft.splice(index, 1)
})

// 根据 id 更新
const updatedTodosArray = produce(todosArray, draft => {
const index = draft.findIndex(todo => todo.id === "id1")
if (index !== -1) draft[index].done = true
})

// 过滤
const updatedTodosArray = produce(todosArray, draft => {
// 过滤器实际上会返回一个不可变的状态,但是如果过滤器不是处于对象的顶层,这个依然很有用
return draft.filter(todo => todo.done)
})

嵌套数据结构

import {produce} from "immer"

// 复杂数据结构例子
const store = {
users: new Map([
[
"17",
{
name: "Michel",
todos: [
{
title: "Get coffee",
done: false
}
]
}
]
])
}

// 深度更新
const nextStore = produce(store, draft => {
draft.users.get("17").todos[0].done = true
})

// 过滤
const nextStore = produce(store, draft => {
const user = draft.users.get("17")

user.todos = user.todos.filter(todo => todo.done)
})

请注意,许多数组操作可用于通过传递多个参数或使用展开操作来一次插入多个元素:todos.unshift(...items)

请注意,当处理包含通常由某个 id 标识的对象的数组时,我们建议使用基于 Map 或索引的对象(如上所示)而不是执行频繁的查找操作,查找表通常执行效率更高。

+ + + + \ No newline at end of file