Search code examples
reactjsreduxreact-reduxredux-toolkit

How to use selectById selector generated from createEntityAdapter


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.


Solution

  • 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.