Easy-peasy: Computed value from store state does not trigger update when using destructuring

Created on 19 Dec 2019  路  5Comments  路  Source: ctrlplusb/easy-peasy

Hi,

I came across this strange bug that I have isolated to be an issue with computed values if and only if the computed value is using the global store state AND you access the computed state property by object destructuring. In this case an update to the global store value does not trigger an update in components using the computed value.

I have created a small app that re-creates the problem here: https://gist.github.com/jakobmulvad/14226b9b6ea7a59644a181d8a43bc5e6

When you click the button you will see that the component that uses the computed value by destructuring are not updated when the action is triggered. If however the component is updated by any other means, it will also update to display the correct computed value.

Thanks for a great framework! I'm really digging it! 鉂わ笍

versions:
node: 12.13.1
react: 16.12.0
react-dom: 16.12.0
easy-peasy: 3.2.3

docs

All 5 comments

useStoreState(state => state.computedModel); and
useStoreState(state => state.computedModel.computedValue); return different values. Your component is updated only if the returned value from mapState function is different.
While those two calls might look the same, they behave differently.

https://stackblitz.com/edit/react-nn9wby

I see. So this is actually expected behavior?

I was assuming that the comparison would be deep - not shallow (meaning if any of the properties of the object returned changed it would trigger an update)

Ok I'll just close this here then.

Thanks for responding

No, that should be the case @jakobmulvad

I am going to investigate. 馃憤

Ok, there are some limitations with computed properties around destructuring. I'll do a big write up here eventually and get the docs queued for an update.

I have updated the docs in the #459 PR.


Computed properties break when destructuring a computed property out of state

Say you had a computed property defined in your model like below.

const storeModel = {
  session: {
    user: null,
    isLoggedIn: computed(state => state.user != null)
  }
}

If you destructure the computed property when accessing it in your component, like below, it will not work.

function LoggedInBadge() {
  const { isLoggedIn } = useStoreState(state => state.session);
  return isLoggedIn ? <LoggedInSvg /> : <LoggedOutSvg />;
}

This is because computed properties are in actual fact getter properties. If you destructure the property you break the getter mechanism. Therefore you may not receive updates to your computed property based on when the state that your computed property depends on updates.

The resolution to this is to instead resolve the computed property directly.

function LoggedInBadge() {
  const isLoggedIn = useStoreState(state => state.session.isLoggedIn);
  return isLoggedIn ? <LoggedInSvg /> : <LoggedOutSvg />;
}
Was this page helpful?
0 / 5 - 0 ratings