How can zustand distinguish between atomics and objects?
See original GitHub issueSo 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)
Issue Analytics
- State:
- Created 4 years ago
- Comments:13 (8 by maintainers)
Top GitHub Comments
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…
…to atomic selection…
… 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?
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:
though if we are shipping this bit, we’d have to ship shallowequal again, and it wouldn’t treeshake like that.