avenger icon indicating copy to clipboard operation
avenger copied to clipboard

queryStrict strategy is not very intuitive

Open veej opened this issue 2 years ago • 4 comments

A query can use two different default strategies to match the cached values: a shallow equality (queryShallow), which compares every first-level field in an object (if the type of the input param is "object"), and a strict equality (queryStrict), which compares the inputs object with just a reference equality (===). However, the strict equality has a very limited usage, since it makes sense only if the query has a single flat parameter (i.e. not wrapped in an object), for example:

const query = queryStrict((foo: string) => apiCall(foo), expires(10000));

If we need to define a query with multiple parameters (that avenger forces us to wrap in a single object), or if we want to pass a single parameter wrapped in an object, it's practically impossible to keep the same reference for the input object, causing a lot of unwanted refetches even if we don't change the references for the single parameters.

const query = queryStrict(({ foo: string, bar: number }) => apiCall(foo, bar), expires(10000))

const foo = "test";
const bar = 20;

<WithQueries
   queries={{ query }}
   params={{ query: { foo, bar } }}    --> since we define a new object every time, 
                                           the input object will never match the cached entry
/>

Moreover, it's not very clear what happens when a query has no parameters. AFAICT, when calling a query without params, we match for an empty input object, that will always have a reference different from the one stored in the cache, so the query will always be refetched in case we use queryStrict.

To be confirmed: it also seems that the observables use always a shallow equality. This means that if two components calls a queryStrict with the same params (but wrapped in an object, so the reference will be different), the cache will not be matched when the last component runs the query, but the refetch will affect both components, since they're observing the same (according to shallow eq) input parameters. If the second component is a child of the first one, the re-rendering of the first component (due to the change of the observed query) may re-render the second, that will re-run the query (not matching the cache), causing again a re-render of the first component and so on, causing an infinite loop of re-renders.

veej avatar Sep 29 '21 17:09 veej