Repository: tannerlinsley/react-query
Pull request #3052 (2021-12-04 20:01:08)

fix(queriesObserver): fix getOptimisticResult, order of returned observers
Fix for `queriesObserver.getOptimisticResult` to correctly call `getOptimisticResult` on the observers. 

This was an issue I introduced in PR #2866. There I had needed to tweak [two](https://github.com/tannerlinsley/react-query/pull/2866/files#diff-27ab6cf11862f134526488fd6c22381bf484a5ad9a6d7dc36535e1d3e2d5aa42R209) [original](https://github.com/tannerlinsley/react-query/pull/2866/files#diff-27ab6cf11862f134526488fd6c22381bf484a5ad9a6d7dc36535e1d3e2d5aa42R131) tests, which now in hindsight were off due to this issue. I now reverted those tests back to the original form.

Now testing the issue, I also noticed a small issue with the order of the observers returned by `findMatchingObservers`: with `keepPreviousData: true`, any repurposed observers would be returned last, potentially in different order than the given queries. 

The fix is just to sort the observer entries by the order of the queries before returning them. This also gets rid of an extra render at least in some tests. As this was a rather small fix, I included the commit for that fix here, but I can also put it in a separate PR if that would be cleaner.

vercel[bot]: This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).  
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/tanstack/react-query/8z5ZSrBPCevLtaoNZ8pKjjyc8MDZ](https://vercel.com/tanstack/react-query/8z5ZSrBPCevLtaoNZ8pKjjyc8MDZ)  
✅ Preview: *In Progress*


codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/tannerlinsley/react-query/pr/3052/builds/195335) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit be6cb127d74fc22f1e013c141be6c2efa948843d:

|Sandbox| Source |
|--|--|
|[tannerlinsley/react-query: basic](https://codesandbox.io/s/tannerlinsley-react-query-basic-blsjf)| Configuration |
|[tannerlinsley/react-query: basic-typescript](https://codesandbox.io/s/tannerlinsley-react-query-basic-typescript-pw8sl)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) Report
> Merging [#3052](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) (be6cb12) into [master](https://codecov.io/gh/tannerlinsley/react-query/commit/5fd537e4c2ad39aa5f36d96736d8426228d16c42?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) (5fd537e) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/tannerlinsley/react-query/pull/3052/graphs/tree.svg?width=650&height=150&src=pr&token=jqEbswkEDQ&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)

```diff
@@           Coverage Diff           @@
##           master    #3052   +/-   ##
=======================================
  Coverage   96.45%   96.46%           
=======================================
  Files          45       45           
  Lines        2259     2261    +2     
  Branches      641      641           
=======================================
+ Hits         2179     2181    +2     
  Misses         77       77           
  Partials        3        3           
```


| [Impacted Files](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley) | Coverage Δ | |
|---|---|---|
| [src/core/queriesObserver.ts](https://codecov.io/gh/tannerlinsley/react-query/pull/3052/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley#diff-c3JjL2NvcmUvcXVlcmllc09ic2VydmVyLnRz) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley). Last update [5fd537e...be6cb12](https://codecov.io/gh/tannerlinsley/react-query/pull/3052?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tanner+Linsley).

TkDodo: > Now testing the issue, I also noticed a small issue with the order of the observers returned by findMatchingObservers: with keepPreviousData: true, any repurposed observers would be returned last, potentially in different order than the given queries.

I actually _did_ notice this in the other PR, but then somehow thought it didn't matter 🙈 

Patch:
diff --git a/src/core/queriesObserver.ts b/src/core/queriesObserver.ts
index 1a32d51e6..2eb22ef8b 100644
--- a/src/core/queriesObserver.ts
+++ b/src/core/queriesObserver.ts
@@ -65,7 +65,7 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
 
   getOptimisticResult(queries: QueryObserverOptions[]): QueryObserverResult[] {
     return this.findMatchingObservers(queries).map(match =>
-      match.observer.getCurrentResult()
+      match.observer.getOptimisticResult(match.defaultedQueryOptions)
     )
   }
 
@@ -121,7 +121,16 @@ export class QueriesObserver extends Subscribable<QueriesObserverListener> {
       }
     )
 
-    return matchingObservers.concat(newOrReusedObservers)
+    const sortMatchesByOrderOfQueries = (
+      a: QueryObserverMatch,
+      b: QueryObserverMatch
+    ): number =>
+      defaultedQueryOptions.indexOf(a.defaultedQueryOptions) -
+      defaultedQueryOptions.indexOf(b.defaultedQueryOptions)
+
+    return matchingObservers
+      .concat(newOrReusedObservers)
+      .sort(sortMatchesByOrderOfQueries)
   }
 
   private getObserver(options: QueryObserverOptions): QueryObserver {


Test patch:
diff --git a/src/react/tests/useQueries.test.tsx b/src/react/tests/useQueries.test.tsx
index f8611c648..305e7af5c 100644
--- a/src/react/tests/useQueries.test.tsx
+++ b/src/react/tests/useQueries.test.tsx
@@ -128,8 +128,8 @@ describe('useQueries', () => {
       { status: 'success', data: 5, isPreviousData: false, isFetching: false },
     ])
     expect(states[3]).toMatchObject([
-      { status: 'success', data: 2, isPreviousData: false, isFetching: false },
-      { status: 'success', data: 5, isPreviousData: false, isFetching: false },
+      { status: 'success', data: 2, isPreviousData: true, isFetching: true },
+      { status: 'success', data: 5, isPreviousData: true, isFetching: true },
     ])
     expect(states[4]).toMatchObject([
       { status: 'success', data: 2, isPreviousData: true, isFetching: true },
@@ -206,8 +206,8 @@ describe('useQueries', () => {
     ])
 
     expect(states[3]).toMatchObject([
-      { status: 'success', data: 4, isPreviousData: false, isFetching: false },
-      { status: 'success', data: 8, isPreviousData: false, isFetching: false },
+      { status: 'success', data: 4, isPreviousData: true, isFetching: true },
+      { status: 'success', data: 8, isPreviousData: true, isFetching: true },
       {
         status: 'loading',
         data: undefined,
@@ -293,7 +293,7 @@ describe('useQueries', () => {
 
     renderWithClient(queryClient, <Page />)
 
-    await waitFor(() => expect(states.length).toBe(10))
+    await waitFor(() => expect(states.length).toBe(9))
 
     expect(states[0]).toMatchObject([
       {
@@ -324,7 +324,7 @@ describe('useQueries', () => {
     ])
     expect(states[3]).toMatchObject([
       { status: 'success', data: 5, isPreviousData: false, isFetching: false },
-      { status: 'success', data: 10, isPreviousData: false, isFetching: false },
+      { status: 'success', data: 10, isPreviousData: true, isFetching: true },
     ])
     expect(states[4]).toMatchObject([
       { status: 'success', data: 5, isPreviousData: false, isFetching: false },
@@ -335,18 +335,14 @@ describe('useQueries', () => {
       { status: 'success', data: 15, isPreviousData: false, isFetching: false },
     ])
     expect(states[6]).toMatchObject([
+      { status: 'success', data: 10, isPreviousData: false, isFetching: true },
       { status: 'success', data: 15, isPreviousData: false, isFetching: false },
-      { status: 'success', data: 5, isPreviousData: false, isFetching: false },
     ])
     expect(states[7]).toMatchObject([
       { status: 'success', data: 10, isPreviousData: false, isFetching: true },
       { status: 'success', data: 15, isPreviousData: false, isFetching: false },
     ])
     expect(states[8]).toMatchObject([
-      { status: 'success', data: 10, isPreviousData: false, isFetching: true },
-      { status: 'success', data: 15, isPreviousData: false, isFetching: false },
-    ])
-    expect(states[9]).toMatchObject([
       { status: 'success', data: 10, isPreviousData: false, isFetching: false },
       { status: 'success', data: 15, isPreviousData: false, isFetching: false },
     ])
@@ -390,7 +386,7 @@ describe('useQueries', () => {
 
     renderWithClient(queryClient, <Page />)
 
-    await waitFor(() => expect(states.length).toBe(9))
+    await waitFor(() => expect(states.length).toBe(8))
 
     expect(states[0]).toMatchObject([
       {
@@ -426,18 +422,14 @@ describe('useQueries', () => {
       { status: 'success', data: 10, isPreviousData: false, isFetching: false },
     ])
     expect(states[5]).toMatchObject([
-      { status: 'success', data: 10, isPreviousData: false, isFetching: false },
       { status: 'success', data: 5, isPreviousData: false, isFetching: true },
+      { status: 'success', data: 10, isPreviousData: false, isFetching: false },
     ])
     expect(states[6]).toMatchObject([
       { status: 'success', data: 5, isPreviousData: false, isFetching: true },
       { status: 'success', data: 10, isPreviousData: false, isFetching: false },
     ])
     expect(states[7]).toMatchObject([
-      { status: 'success', data: 5, isPreviousData: false, isFetching: true },
-      { status: 'success', data: 10, isPreviousData: false, isFetching: false },
-    ])
-    expect(states[8]).toMatchObject([
       { status: 'success', data: 5, isPreviousData: false, isFetching: false },
       { status: 'success', data: 10, isPreviousData: false, isFetching: false },
     ])