-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
#1775 caused useQueries to return unstable values between render cycles #1905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Versions after |
it was mentioned here, in 3.9.0 for concurrent mode safety:
is |
Then I didn't do my homework. I apologize for that.
I don't actually know that because my code was relying on the returned array being referentially stable. I think I will be able to work around this issue for now by using The documentation for |
yes, would you like to do that? It's also the case for |
It would likely be useful to have a page where the referential stability of the hooks is discussed. With I can try writing a new page, or just extend the existing pages. Maybe it is better to extend the existing pages. What do you think? |
sure, please open a PR that addresses it in the docs, extending the existing pages is fine. I'll close this issue. |
That is quite a huge (see: disastrous) change that was introduced. It's unclear to me what the use for Edit: also a breaking change in a minor version is not a great look |
The use case is to run a variable amount of queries. I don't see what referentially stable return values have to do with this?
I don't see the library guaranteeing to return the same array in every render, so it's technically not a breaking change ;) On a more serious note, I see that this change is more severe for
while with useQueries, you would get a new array every time, and even if you
@jcready maybe you can outline your use-case a bit, what you are doing with the result of |
You don't see what referentially stable return values for
That's not what defines a breaking change. In fact, the maintainers of this library were well aware of the breaking change and introduced it in a minor version bump anyways:
Just look at all the tickets that point back to #1775
The use-case is pretty straight forward. Use the result of For anyone looking for a way to work around this breaking change this is what I've had to setup:
This solution is definitely sub-optimal and may not handle every case, but it's better than the alternative: running even more expensive operations on the unstable |
yes, I think the tradeoff of making the library adhere to the "rules of react" (no side effects during render), also dubbed as "works in concurrent mode" trumped the referential stability. I'm sorry if this has caused a headache for you. Its debatable if it is considered a breaking change imo, but that ship has sailed. Maybe we can revisit the implementation once React 18 comes out and we have access to things like useSyncExternalStore the largest use case for useQueries is still rendering the result of multiple queries:
since
maybe this can help you move the expensive part of your calculation into select which then potentially leaves you with a non-expensive aggregation (again, depends). finally, still not ideal, but if the number of queries is known, you can destruct data and work with multiple of those. |
Is latest react-query now making use of |
v4 does, yes. |
It still seems like For context (pun unintended), I'm willing to save a query with user login data in the application's context. According to the eslint rule |
the top level object that's returned from |
Is it something that is likely to change sometime? As I described, this behavior makes keeping queries in context inefficient. It is usually desired to keep them in contexts so you could render its different states (loading and error), rather than just displaying the data. |
I don't think there are good reasons to put the whole query result into context. Are you aware that you can just call useQuery wherever you want to get the data? Maybe state what problem you're trying to solve with putting it in context... |
I'm aware, and it does solve the problem I'm describing. But just for convenience: Consider a function UserContextProvider({children}: {children: ReactNode}) {
const userQuery = useQuery(['user'], () => getUser());
const userPreferences = useUserPreferences();
// ... other user-related things
const value = useMemo(() => ({
userQuery,
userPreferences,
}), [userQuery, userPreferences]);
return (
<userContext.Provider value={value}>
{children}
</userContext.Provider>
);
} Let's say you have two places where you render a user's name - in the header and the comments section. I find it right to store user-related data in such The only other way to access the same query object (with the same dependencies, logic and query options) in multiple parts of the app, is to wrap your usage of function useUser() {
return useQuery(['user'], () => getUser(), {
// ...arbitrary options
});
} Due to which. other user data (such as preferences) is separated from other user data sources. I find it simpler to access "everything user" from a single place: the user context. |
this is pretty much the same, just without actual "context" ? |
I agree it will work in this game, but once you add a state (what if |
then you would probably put that state into context and then make a custom hook that reads from this context + from useQuery to combine the two. But there is no reason to put the query itself into context. Basically, you have two things (A + B) and you want to derive something from that (C) and put that into context, whereas I would put just A in context and derive C on the fly (with a hook) from Context + B (B being the query here). For the consumers, nothing changes because it doesn't matter if a hook only reads from context or does more things. |
Because it's a React library, and React works based upon referentially stable values. This also caused 100% CPU usage infinite loop on my end, which was very hard to debug. The use case is exactly as stated. Variable number of queries. Even if I Perhaps you could elaborate on the problem with having useQueries return a stable array? Seems like you believe making the array stable causes bugs (and want to save your users from these bugs). Users are going to make the array stable anyways via workarounds because they don't understand the bugs. If there are bugs, it would be helpful to explain that better for us (and the alternative approach so we can implement our use case?). If there are not bugs, it would be helpful for the lib to make the array stable for us so we don't have to employ workarounds on our own. |
in v5, you can use the result is structurally shared, so it will be stable across re-renders. |
Still seems like it would be nice for the original array to just be stable in the first place (or understand why it causes an issue for it to not be stable) as that feels like a "workaround" is still required, the default behavior of adopting the |
those examples usually involve |
Describe the bug
The array returned by
useQueries
is not stable between render cycles which makes it unusable for anything down the line that uses shallow equality to determine if something had changed.Small snippet to illustrate the bug
Console output
Expected behavior
The return value of
useQueries
is stable between render cycles as long as the queries did not change. The returned value can be used as a dependency for hooks likeuseMemo
/useEffect
which use shallow equality checks to determine if a dependency had changed since the last renderDesktop (please complete the following information):
Additional context
The new behavior was introduced via #1775.
Relevant code lines:
https://github.com/tannerlinsley/react-query/blob/f2137dc4e4553256c4ebc1891b548fe35efe9231/src/react/useQueries.ts#L29
https://github.com/tannerlinsley/react-query/blob/f2137dc4e4553256c4ebc1891b548fe35efe9231/src/core/queriesObserver.ts#L67
The text was updated successfully, but these errors were encountered: