zustand/docs/guides/updating-nested-state-object-values.md
Jacob Bergholtz 4ed81bc11b
Add usage with context to docs (#1291)
* docs: context guide proposal

* fix(docs): typo & omit comment

* fix(docs): remove horizontal rules

* fix(docs): add wiki link to DI

* fix(docs): format with prettier

* fix(docs): cases that model => where... is needed

* fix(docs): use sentence case

* fix(docs): omit quote block

* fix(docs): into "a" custom hook

* fix(docs): format with prettier

* fix(docs): sort broken nav indexes

* Update docs/guides/initialize-state-with-props.md

Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>

* fix(docs): reintroduce React.createContext example

* scripts: escape quotes

* styles: run prettier

* fix(docs): omit 'React' from imports

* styles: run prettier

* styles: run prettier

Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
2022-09-18 09:01:06 +09:00

1.7 KiB

title nav
Updating nested state object values 3

Deeply nested object

If you have a deep state object like this:

type State = {
  deep: {
    nested: {
      obj: { count: number }
    }
  }
}

It requires some effort to update the count value immutably.

Normal approach

The normal approach is to copy state object with the spread operator ... like so:

  normalInc: () =>
    set((state) => ({
      deep: {
        ...state.deep,
        nested: {
          ...state.deep.nested,
          obj: {
            ...state.deep.nested.obj,
            count: state.deep.nested.obj.count + 1
          }
        }
      }
    })),

This is very long!

With immer

Many people use immer to update nested values. You can use immer to shorten your state updates for deeply nested object like this:

  immerInc: () =>
    set(produce((state: State) => { ++state.deep.nested.obj.count })),

What a reduction!. Please take note of the gotchas listed here.

With optics-ts

There is another option with optics-ts:

  opticsInc: () =>
    set(O.modify(O.optic<State>().path("deep.nested.obj.count"))((c) => c + 1)),

Unlike immer, optics-ts doesn't use proxies or mutation syntax.

With ramda

You can also use ramda:

  ramdaInc: () =>
    set(R.over(R.lensPath(["deep", "nested", "obj", "count"]), (c) => c + 1)),

Both ramda and optics-ts also work with types.

CodeSandbox Demo

https://codesandbox.io/s/zustand-normal-immer-optics-ramda-updating-ynn3o?file=/src/App.tsx