0

I have set up RTK Query as an API layer within my application. This replaced data previously stored in redux which was being used to build selectors (using CreateSelector from reselect).

Now with RTK Query, everything is in hooks, so naturally I attempted to move the logic in CreateSelector to various hooks being sourced with RTK Query results like so:

useSelectStoreDetailedData = () => {
    const {storesData} = useListStoresQuery()
    const {productsData} = useListProductsQuery()
    const {pricesData} = useListPricesQuery()
    return useMemo(()=> runExpensiveFunc(storesData, productsData, pricesData), 
     [storesData, productsData, pricesData])
}

This works fine when 1 component is calling this hook, but if many components need this data, each component making a call to the hook (i.e. useSelectStoreDetailedData()) causes the data to be reprocessed from scratch since it's mounting another instance of the hook. Since it's a very expensive operation, this is causing the application to visibly slow down.

I've tried taking this expensive function and memoizing it using lodash memoize function but it's also a costly operation to determine equality.

Is there some better pattern for sharing this api-sourced computation across components?

DannyMoshe
  • 6,023
  • 4
  • 31
  • 53

1 Answers1

1

You could just use your reselect selector.

const selector = createSelector(...)


useSelectStoreDetailedData = () => {
    const {storesData} = useListStoresQuery()
    const {productsData} = useListProductsQuery()
    const {pricesData} = useListPricesQuery()
    return selector(storesData, productsData, pricesData)
}
phry
  • 35,762
  • 5
  • 67
  • 81
  • The old selector looks like ```selectStoreDetailedData = createSelector([storeSelector, productSelector, priceSelector], (stores, products, prices) => {...})```, when i try calling it directly (as you recommend) It fails trying to execute the old selector (i.e. storeSelector). Am I missing something? – DannyMoshe Mar 15 '22 at 00:17
  • 1
    Your old selector probably assumes to get a state and to extract the data from that - which you pretty much already have done. So you'd need to rewrite it a bit to accept multiple arguments - give the docs a short read. My main point was that as a "memoisation mechanism", you can use your existing knowledge about reselect and just continue using reselect. It's fine as a memoisation tool, even without direct redux contact. – phry Mar 15 '22 at 09:41
  • If i understand correctly, the way to do this is to package my data into an object and call the selector with a payload like this -```{param1: param1Data, param2: param2Data}```, then extract it within the create selector function - ```createSelector([data=>data.param1, data=>data.param2], (param1, param2) => myFunc(param1, param2))``` is this correct? Or is there a better approach – DannyMoshe Mar 16 '22 at 04:52
  • 1
    There is also `createSelector((p1)=>(p1), (_, p2) => p2), (param1, param2) => myFunc(param1, param2))` as an option. – phry Mar 16 '22 at 07:45