How to use selectById selector generated from createEntityAdapter

Viewed 6588

All examples on redux-toolkit website show usage of either selectIds or selectAll. Using either of them is simple. I have a redux-slice from where I am exporting

export const {
  selectById: selectUserById,
  selectIds: selectUserIds,
  selectEntities: selectUserEntities,
  selectAll: selectAllUsers,
  selectTotal: selectTotalUsers
} = usersAdapter.getSelectors(state => state.users)

then I am importing the selectors in my components and using like

const valueIAmInterestedIn = useSelector(selectUserIds)

I am interested in the code related to the usage of selectUserById.

2 Answers

According to the documentation the by id selector has the following signature: selectById: (state: V, id: EntityId) => T | undefined.

So you can call it in your component in the following way:

const Component = ({ id }) => {
  const item = useSelector((state) =>
    selectUserById(state, id)
  );
};

This implementation of "normalization" may not work if you sort/filter entities on the server because the state would look more like:

{
  data: {
    entityType: {
      //query is key and value is status and result
      //  of the api request
      'sort=name&page=1': {
        loading: false,
        requested: true,
        error: false,
        stale: false,
        ids: [1, 2],
      },
      'sort=name:desc&page=1': {
        //would have loading, requested ....
        ids: [2, 1],
      },
      data: {
        //all the data (fetched so far)
        '1': { id: 1 },
        '2': { id: 2 },
      },
    },
  },
};

I have not worked with the "helpers" so have to look into it as it may facilitate for server side filtering and sorting.

I also doubt it will memoize the selector:

const List = ({ items }) => (
  <ul>
    {items.map(({ id }) => (
      <Item key={id} id={id} />
    ))}
  </ul>
);
const Item = React.memo(function Item({ id }) {
  //selectUserById is called with different id during
  // a render and nothing will be memoized
  const item = useSelector((state) =>
    selectUserById(state, id)
  );
});

I have created a short documentation on how you can use selectors created with reselect.

Selector can be created on top of selectById as below:

export const getLanguageById = (entityId: number) => {
  return createSelector(selectLanguageState, (state) =>
    selectById(state, entityId)
  );
};

This can be used in your component as below:

const language = useSelector(languageSelectors.getLanguageById(18));

I guess it's more straightforward and easy to read/ understand.

Thanks, Manish

Related