Reputation: 175
I have a series of components which all use data derived from an RTK Query response. While derived from the same response with the same query arguments, each component needs the data to pass through a set of relatively expensive client-side filters (whose args are redux store slice properties) which may not be the same for each component. However, all of the components require the data to pass through at least two specific filters. This relationship is shown by the following diagram:
Is it possible to subscribe to the data after it has been transformed by a specific filter/ set of filters?
Approaches I have considered:
extraReducers
option and listen for query completion, then perform filter operation. This works fine since i can use the filter args in the reducer, but I believe there is no way for me to repeat the operation with new args once the filter args have been updated but the query data has stayed the same.Intuitively i would think some callback that operates as some middleware between the API result and the component's subscribed data would be ideal. I am aware of the transformResponse option definable in the API slice, but I believe it is not appropriate or possible for this situation.
const queryResult = endpointName.useQuery(args, filterArgs, (data, filterArgs) => {
return data.performSomeSharedFilterOperationHere(filterArgs);
}
);
Ideally the data would update when query args change OR when filter args change. I suppose the difference between this and a simple useEffect implementation is that in the useEffect scenario, the data is not 'shared' and the filter operations occur nSubscribedComponents times.
Is there anything in RTK that permits the behavior I am seeking?
Upvotes: 3
Views: 5504
Reputation: 67439
I think the right answer here is to use the selectFromResult
option in the query hooks.
Create the following Reselect selectors:
const selectFilter1 = createSelector(
// Start by taking the actual response data as its input
(inputData) => inputData,
(data) => // magically transform here
)
const selectFilter2 = createSelector(
selectFilter1,
(filteredData) => // magically transform here
)
// repeat for filters 2 and 3
Then, in the component:
const { filteredData} = useGetPostsQuery(undefined, {
selectFromResult: result => ({
// We can optionally include the other metadata fields from the result here
...result,
// Include a field called `filteredData` in the result object,
// and memoize the calculation
filteredData: selectFilter3(result.data)
})
})
The components will be sharing the same selector instance, so each time the selector is called the same result.data
reference should be passed in, and thus the calculations should memoize. The first couple selectors should memoize their results, and thus selectFilter3
will only have to recalculate when selectFilter2
's result changes, etc.
Upvotes: 6