No, they are not identical: the first will re-render only when the selected properties change; and the second will re-render whenever any property of the store changes.
The motivation for the question seems to be to avoid the verbosity of fetching multiple states with Zustand (as ICW also commented, this can be a pain.)
You can achieve a more concise syntax for multiple zustand imports in a couple of different ways.
Option 1
Let's define this helper function:
function useMulti(useFunc, ...items) {
return items.reduce((carry, item) => ({
...carry,
[item]: useFunc(state => state[item]),
}), {})
}
After defining this wrapper function, instead of writing this:
const {nuts, honey} = useStore(state => ({
nuts: state.nuts,
honey: state.honey,
}), shallow)
you can write this:
const {nuts, honey} = useMulti(useStore, 'nuts', 'honey')
The wrapper function is just providing some syntactic sugar for selecting multiple states.
- Note that internally,
useMulti
uses a separate useStore
call for each asked-for prop. Therefore, state invalidation is equivalent to using zustand/shallow
without useMulti
.
- Also note that
useMulti
only works for top-level properties of the store: you would need a more complicated useMulti
implementation if you want to fetch state.x.y.z
, for example.
If you don't like the functional call style of useMulti(useStore(...))
, you can leverage useMulti()
to create a wrapper function for useStore()
specifically:
export const useStoreMulti = (...items) => useMulti(useStore, ...items)
This allows you to write
const {nuts, honey} = useStoreMulti('nuts', 'honey')
Option 2
It can be cleaner to just import them separately. This is particularly true if you're selecting many different store props: consider the following, where zustand is quite verbose:
const {
nuts,
honey,
salmon,
berries,
fruit,
insects,
carrion,
newbornElk,
roots,
garbage,
} = useStore(state => ({
nuts: state.nuts,
honey: state.honey,
salmon: state.salmon,
berries: state.berries,
fruit: state.fruit,
insects: state.insects,
carrion: state.carrion,
newbornElk: state.newbornElk,
roots: state.roots,
garbage: state.garbage,
}), shallow)
vs this, which is broadly equivalent:
const nuts = useStore(state => state.nuts)
const honey = useStore(state => state.honey)
const salmon = useStore(state => state.salmon)
const berries = useStore(state => state.berries)
const fruit = useStore(state => state.fruit)
const insects = useStore(state => state.insects)
const carrion = useStore(state => state.carrion)
const newbornElk = useStore(state => state.newbornElk)
const roots = useStore(state => state.roots)
const garbage = useStore(state => state.garbage)
One way to reduce the number of characters per call here is to define a local helper:
const localUse = (prop) => useStore(state => state[prop])
const nuts = localUse('nuts')
const honey = localUse('honey')
const salmon = localUse('salmon')
const berries = localUse('berries')
const fruit = localUse('fruit')
const insects = localUse('insects')
const carrion = localUse('carrion')
const newbornElk = localUse('newbornElk')
const roots = localUse('roots')
const garbage = localUse('garbage)