reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.76k stars 1.18k forks source link

Question: Rtk Endpoint Hook Called In Component Loop #4710

Closed rdeanmcdonald closed 2 days ago

rdeanmcdonald commented 1 week ago

Hi folks! I have an RTK question, hope this is the right place to ask it. I've got an RTK endpoint definition that looks something like:

export const apiSlice = createApi({
    baseQuery: fetchBaseQuery({
        ...
    }),
    tagTypes: [
        "Customers",
    ],
    endpoints: (builder) => ({
        getCustomersByDriverIds: builder.query<
            Customer[],
            GetCustomersByDriverIdsParams
        >({
            query: ({ driverIds }) =>
                `/customers?${driverIds
                    .map((did) => `driverIds=${did}`)
                    .join("&")}`,
            providesTags: ["Customers"]
        }),
    })
});

I have a react component that allows you to select/deselect multiple customers. Select/Deselect/Bulk Select/Bulk Deselect.

Its works well with the above RTK definition, using something like this in the component:

    const selectedTerritoryDriverIds = useAppSelector(selectedTerritoriesSelector);
    const { data: customersByDriverId } = useGetCustomersByDriverIdsQuery(
        {driverIds: selectedTerritoryDriverIds},
    );

The problem is, the caching isn't working well. E.g. if you select all customers, it makes a query/cache entry for:

/customers?driverId=123&driverId=456&driverId=789&...

And lets say I deselect a single customer (e.g. customer 123), then this query is made:

/customers?driverId=456&driverId=789&...

So another query, and another cache entry with data that all was already fetched.

I've been trying to get this excessive query/caching to be better, but am struggling. I keep thinking there must be a way this is supposed to be done with RTK but I can't find anything!

Any pointers would be very much appreciated!

Some things I've thought of doing but either can't or it's really ugly:

  1. Make a call to /customers?driverId=??? for 1 driver at a time, in a loop, but I can't use the hook inside a loop in the component.
  2. Use the lazyQuery, then I can do it in a loop, but now invalidation doesn't trigger component re-rendering as I'd like.
  3. Create a separate redux slice, bypassing RTK to take care of this logic. (would be fine but just keep thinking RTK would already have a pattern for this type of use case that I should be using)
  4. Use queryFn instead of query in RTK, where I can check the endpoint state. But then handling invalidation is impossible (unless I'm missing something, I don't see any invalidating state in the rtk state)