chrisvander / zustand-computed

A Zustand middleware to create computed states.
MIT License
82 stars 8 forks source link

Order of middleware when using computed with immer (plus nested state) #36

Open tchock opened 3 days ago

tchock commented 3 days ago

Hello,

I'm trying to compose the computed middleware with immer and in the README example it shows the middleware being in the order of immer(computed(...)). But when I do that the state is an immer Proxy and the immer middleware expects the state to be modified by setting the value directly instead of returning a the whole state object.

When I change the order to computed(immer()) it works, but then with the return pattern.

I would love to have support for the immer pattern as I have nested state objects. Something like this:

const computed = createComputed((state) => {
  state.basket.total = calculateBasketTotal(state);
});

The above example fails because it's not returning anything and zustand-computed is trying to go through the keys of the returned object.

Because of the nested state I need to do something like this:

const computed = createComputed((state) => ({
  basket: {
    ...state.basket,
    total: calculateBasketTotal(state),
  },
}));

If the immer pattern is not working, maybe a merge with existing state would work? So that I could do this (and it would merge it with the existing basket object):

const computed = createComputed((state) => ({
  basket: {
    total: calculateBasketTotal(state),
  },
}));

I know this is multiple things in one issue. If one of the approaches would be feasable to you I can also make a new one describing only this approach.

Otherwise for the meantime maybe update the readme with the right order and show a sample content for the compose function, so it's clear it expects a return value and doesn't use the immer modification approach.

tchock commented 3 days ago

Just looked through solutions that could be used to do nested comparison for changes: proxy-compare from dai-shi from the immer team would do exactly that :)