ctrlplusb / easy-peasy

Vegetarian friendly state for React

Home Page:https://easy-peasy.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use typed useStoreState with dependencies (v3.0.2)

redjonzaci opened this issue · comments

This is my first issue here and I don't know if this is the right place to ask.

We are using v3.0.2 in a company project and I needed to run useStoreState only once, but it returns an object.
I saw that the typed useStoreState has dependencies?: any[] | undefined as second parameter.

//         don't know what to put here 🔽
useStoreState(state => state.premiums, [])
// premiums is an object

It hasn't been documented in the official docs and I don't know what values to use it with.
I also saw some documentation on an equalityFn as a second parameter,
but it wasn't defined either in the typed hook or otherwise.

I would appreciate some help.

Hi @redjonzaci, I'm not a maintainer of or contributor to easy-peasy, but my guess would be that this is a mistake with the TypeScript types as the useStoreState hook shouldn't have or require any dependencies to work properly. In version 3.x, the only documented second param is an equality function which can be used to prevent unwanted re-renders when returning non-atomic values from the hook. See here and here.

In your example, you shouldn't need the second param at all, but if you were doing something like this:

  const { item1, item2 } = useStoreState(
    state => ({
      item1: state.items.item1,
      item2: state.items.item2,
    })
  )

Your component would re-render every time any state changes because the default strict equality check would always return false for reference based values. Instead you'd pass a equality function as the second param which supports comparing two references that may contain the same underlying values, such as shallowEqual or lodash's isEqual.

Based on the types for this hook found in version 3.0.2, TypeScript won't allow you to do this, so to be sure this is in fact a mistake with the types you could try just TS-ignoring the error you get from passing in the wrong type and see if easy-peasy itself throws any errors. Also try adding a console.log in a component which maps multiple values and toggling on and off the second param - you should notice a difference in how often the component renders:

import { useStoreState } from 'easy-peasy';
import shallowEqual from 'shallowequal';

function MyComponent() {
  console.log("Did Render");
  // without an equality function you should notice that this
  // component renderes every time the store is updated

  const { item1, item2 } = useStoreState(
    state => ({
      item1: state.items.item1,
      item2: state.items.item2,
    }),
   shallowEqual // @ts-ignore the error from this line and comment it out to test how often the component renders
  )

}

@no-stack-dub-sack thanks for the investigation👍

As you said, the useStoreState hook shouldn't have or require any dependencies to work properly. And the type definition seems to be incorrect in v3.

The current type implementation seems to be correct. I'm closing this for now.