question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How can zustand distinguish between atomics and objects?

See original GitHub issue

So this is something that @dm385 found by accidentally mutating a state object: https://codesandbox.io/s/strange-dew-4gv6k

const [useStore] = create((set, get) => ({
  nested: { a: { a: 1  } }
  actions: {
    inc: () => {
      const nested = { ...get().nested }
      nested.a.a = nested.a.a + 1
      set({ nested })

function Test() {
  const nested = useState(state => state.nested)

Curiously the useStore hook doesn’t fire when inc() is called. It mutates state, and if that weren’t the case it would work, but the nested object is being exchanged here, so i was wondering why the hook didn’t respond:

We distinguish between two selects, atomics and objects:

// Object pick
const { number, string } = useStore(state => ({ number: state.number, string: state.string }))
// Atomic picks
const number = useStore(state => state.number)
const string = useStore(state => state.string)

I’ve never thought about this before, but it actually goes into the objects we return every time to make a shallow equal test, if they’re self-made, like above, or if we select them right from state:

// Doesn't do plain reference equality here, it will check each object prop for ref equality instead
const object = useStore(state => state.object)

The outcome is the same of course, if an object gets changed, even deeply, some prop is going to be different due to reducing. So at least we’re safe, if users don’t mutate it works, but can this lead to performance problems? For instance if a hash map object has 100.000 props it will have to go through them… : S

In Redux the hook does only a strict equality check by default, see: https://react-redux.js.org/api/hooks#equality-comparisons-and-updates Is this something we should do? And since we can’t change the call signature since the 2nd arg is already given to dependencies, would this make sense?

useStore(selector, deps)
useStore.shallow(selector, deps)
api.subscribe(selector, callback)
api.subscribe.shallow(selector, callback)

@JeremyRH

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
timkindbergcommented, Jul 16, 2019

In my project at work, I upgraded zustand to 1.0.2 in a PR and it has been merged to master. Some other devs are noticing that their parts of the app are working differently with some bugs occurring, we think due to the upgrade.

They noticed that if they changed from object selection…

import shallow from 'zustand/shallow'
const { foo, bar } = useMyStore(s => ({ foo: s.foo, bar: s.bar }), shallow)

…to atomic selection…

const foo = useMyStore(s => s.foo)
const bar = useMyStore(s => s.bar)

… that the bugs went away.

Question: Do you expect those two snippets above to work identically in regards to how the component will behave and re-render?

1reaction
drcmdacommented, Jun 30, 2019

tim, could you try atomic picks for a while and see how it’s going?

the problem is that while it somewhat worked, it was also kind of broken, and if your store has larger objects, it will eventually affect performance, since it has to go through all props to figure out changes.

to make shallow equal a default wouldn’t be much more than this:

import create from 'zustand'
import shallowequal from 'shallowequal'

create.shallow = (...args) => {
  const [useStore, api] = createImpl(...args)
  return [(sel, equalityFn = shallowequal) => useStore(sel, equalityFn), api]
}

though if we are shipping this bit, we’d have to ship shallowequal again, and it wouldn’t treeshake like that.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can zustand distinguish between atomics and objects? #36
We distinguish between two selects, atomics and objects: // Object pick const { number, string } = useStore(state => ({ number: state.number ...
Read more >
Zustand's Guide to Simple State Management - Bits and Pieces
These two contrasting approaches. Jotai aims to provide a simple solution for useState and useContext by creating an atomic state (just like ...
Read more >
Comparison — Jotai, primitive and flexible state management ...
Jotai state consists of atoms (i.e. bottom-up). Zustand state is one object (i.e. top-down). Technical difference. The major difference is the state model....
Read more >
A look into React state management in 2021 - Medium
To summarise, Zustand builds on top of great ideas from Redux and simplifies the flux pattern while having a small API and bundle...
Read more >
Using Zustand with React JS! - DEV Community ‍ ‍
The create function takes a callback function as a parameter, which returns an object, to create the store. import create from 'zustand'; export ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found