Open kplatis opened 2 years ago
@kplatis Can you give an example of what you mean by "the more filters I have, the slower Redux becomes"? Ideally as a runnable CodeSandbox or a repo, with some pointers to what's happening.
Can I access the filters directly in queryFn ?
You should not, but go through the arguments - otherways we would not know when arguments update and need a new request to be made.
Hello, answering to your questions:
- The more filters I have, the slower redux becomes. Can I do something for it?
- Can I access the filters directly in queryFn ?
For filters, you can get them this way, its way simple:
const [filterOne, filterTwo] = useSelector((state) => state.filters):
you can pass the whole array as arg to use useQuery hook, like this
const {isLoading, isFetching, data} = useGetResourcesQuery(filters);
As for your question, about accessing filters directly inside queryFn
, based on docs there is a second argument in queryFn()
, called api
, it contains getState()
, so you can do:
getResources: builder.query({
queryFn: (filters, {getState} ) => {
return getResourcesBasedOnFilters(getState().filter.selectedFilter1, getState().filter.selectedFilter2)
},
}),
With this solution:
As for your question, about accessing filters directly inside
queryFn
, based on docs there is a second argument inqueryFn()
, calledapi
, it containsgetState()
, so you can do:getResources: builder.query({ queryFn: (filters, {getState} ) => { return getResourcesBasedOnFilters(getState().filter.selectedFilter1, getState().filter.selectedFilter2) }, }),
It won't refetch when the filters change right?
- When a filter changes, a new request is executed to fetch resources
It would be really nice to have some feature in the library to define dependencies like this on the API instead of in the hook. The component doesn't technically need to know anything about the "base" params of a fetch.
To clarify, the idea from my previous comment could look something like this:
getResources: builder.query({
selectFromState: (state) => {
// Use some selectors here
},
queryFn: (args, {selection} ) => {
return getResourcesBasedOnFilters(selection.filters)
},
})
Basically subscribing the endpoint to Redux state directly instead of having to go through the component.
RTKQ should merge args
and selection
for the cache key.
It might even be a good idea to use createStructuredSelector
here:
getResources: builder.query({
selectFromState: createStructuredSelector({
filters: getFilters,
}),
queryFn: (args, {selection} ) => {
return getResourcesBasedOnFilters(selection.filters)
},
})
For me this would be very helpful to work with app-wide state like auth, landing parameters, global filters.
Honestly, I am pondering about an API like this for a year now - and it would be a consequential next step.
It would add two levels of complexity:
We could avoid 1. by using an api like
getResources: builder.query({
// could also be used in `query`
queryFn: (args, {select} ) => {
const filters = select(getFilters)
return getResourcesBasedOnFilters(filters)
},
})
instead - that would not add any TypeScript overhead.
But from that point, we would have to even track multiple selectors. Nontheless, I think this one would be the way to go.
The bummer is: at the moment I don't have the time to implement anything like that. It's just too much going on for an endeavor of that size.
We only want to refetch when relevant state changes. I was assuming that the selection would need to be outside queryFn
(or query
) to be able to track and trigger new fetches when needed. How would that work with adding select
to the api param? (I may be missing some context about how things work under the hood)
Thanks for considering, perhaps there are "lighter" solutions, I'm just shooting from the hip from the outside here.
@GriffinSauce : one option, if perhaps a bit unwieldy, would be to add a listener middleware entry that watches the relevant bits of state using the predicate
option, and specifically triggers refetching
It won't refetch when the filters change right?
Just for clarity and to answer your question @GriffinSauce:
It will not refetch if the filters are changed, and as I see it you also lose the convenience of the skip
logic here when you implement the query using queryFn
.
This concept of adding dependencies/selectors to the endpoints would be a great addition to the library! I, unfortunately, have no clue on where to begin in implementing something like it 😅
@Vanluren filters
in that case was the argument passed in by the hooks and that will definitely cause a refetch (unless data for those new filters is already in the cache)
I'm a bit confused by the last comments @phryneas - we can already pass filters through arguments. Maybe we're missing some context here about your solution?
It will not refetch if the filters are changed
This is specifically what I'd like to have: responding to state changes without wiring it through the hook arguments.
Thanks for the comments to far 🙏
Glad I found this! I have been spinning my wheels for a while trying to figure out how to access redux state (via a selector) either IN the query method or have it passed down to it from a custom base query via meta or extraOptions but I have not been successful. It seems like what I want is not possible. I want to second @GriffinSauce 's idea to access state variables within the query method.
An example of my use case would be something simple like this:
query: (arg, { getState }) => {
const state = getState();
const userName = selectUserName(state);
// Option 1: return `/some/path/?&userName=${userName}`
// Option 2 return {
url: '/some/path/',
params: { username: userName },
};
},
I know this is not 100% correct but something to this effect. I currently have to select userName from the store in every component where I need to pass userName as an argument to a query hook. It's starting to be duplicated a lot more than I'd like and I thought it would be nice to be able to just grab it at the endpoint definition.
i have a code but dont know how to fix it . Recently trying to use rtk query i need to dynamically change the select() params according to which my filter api will call and have data
import { apiSlice } from "./apiSlice";
const vrpListAdapter = createEntityAdapter({
selectId: (vrp) => vrp.request_id,
});
const initialState = vrpListAdapter.getInitialState();
export const vrpListSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getVrpList: builder.query({
query: ({ seller_id, status }) =>
`/vrp?seller_id=${seller_id}&status=${status}`,
transformResponse: (responseData) => {
const loadedVrpList = responseData.data;
console.log(loadedVrpList);
return vrpListAdapter.setAll(initialState, loadedVrpList);
},
providesTags: (result, error, arg) => [
{ type: "Vrp", id: "vrpList" },
...result.ids.map((id) => ({ type: "Vrp", id })),
],
}),
}),
});
export const { useGetVrpListQuery } = vrpListSlice;
export const createSelectsVrpListResult = (seller_id, status) => {
return vrpListSlice.endpoints.getVrpList.select({ seller_id, status });
};
export const selectsVrpListResult = (state) => {
return createSelectsVrpListResult(
state.vrpFilter.seller_id,
state.vrpFilter.status
)(state);
};
const selectVrpListData = createSelector(
selectsVrpListResult,
(vrpListResult) => vrpListResult.data
);
export const {
selectAll: selectVrpList,
selectById: selectVrpById,
selectIds: selectVrpIds,
} = vrpListAdapter.getSelectors(
(state) => selectVrpListData(state) ?? initialState
);
now everything is fine but i am getting a warning
An input selector returned a different result when passed same arguments.
This means your output selector will likely run more frequently than intended.
Avoid returning a new reference inside your input selector, e.g.
createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)
i am not able figure out how to use create selector i want to have seller_id and status which is there in vrpFilter reducer somehow i didi it but its not optimal please help!!!!!
Hello there. I have recently started using RTK query to fetch and cache my data in my frontend and I have some questions. My use case is the following:
queryFn
instead ofquery
since I fetch data in a custom wayThe api is defined as following:
And I call it using:
RED-14