Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

(fix) - Delay invalidation in ssrExchange by a tick (#885)

* (fix) - Delay invalidation in ssrExchange by a tick

Resolve #874

* Update ssr.test.ts

authored by

Phil Plückthun and committed by
GitHub
93e365d8 c6fb74ed

+25 -8
+5
.changeset/six-pumas-taste.md
··· 1 + --- 2 + '@urql/core': patch 3 + --- 4 + 5 + Fix `ssrExchange` invalidating results on the client-side too eagerly, by delaying invalidation by a tick
+3 -1
packages/core/src/exchanges/ssr.test.ts
··· 119 119 expect(onPush).toHaveBeenCalledWith(queryResponse); 120 120 }); 121 121 122 - it('deletes cached results in non-suspense environments', () => { 122 + it('deletes cached results in non-suspense environments', async () => { 123 123 client.suspense = false; 124 124 const onPush = jest.fn(); 125 125 const ssr = ssrExchange(); ··· 132 132 133 133 pipe(exchange, forEach(onPush)); 134 134 next(queryOperation); 135 + 136 + await Promise.resolve(); 135 137 136 138 expect(Object.keys(ssr.extractData()).length).toBe(0); 137 139 expect(onPush).toHaveBeenCalledWith(queryResponse);
+14 -6
packages/core/src/exchanges/ssr.ts
··· 84 84 export const ssrExchange = (params?: SSRExchangeParams): SSRExchange => { 85 85 const data: SSRData = {}; 86 86 87 + // On the client-side, we delete results from the cache as they're resolved 88 + // this is delayed so that concurrent queries don't delete each other's data 89 + const invalidateQueue: number[] = []; 90 + const invalidate = (result: OperationResult) => { 91 + invalidateQueue.push(result.operation.key); 92 + if (invalidateQueue.length === 1) { 93 + Promise.resolve().then(() => { 94 + let key: number | void; 95 + while ((key = invalidateQueue.shift())) delete data[key]; 96 + }); 97 + } 98 + }; 99 + 87 100 const isCached = (operation: Operation) => { 88 101 return !shouldSkip(operation) && data[operation.key] !== undefined; 89 102 }; ··· 131 144 ); 132 145 } else { 133 146 // On the client we delete results from the cache as they're resolved 134 - cachedOps$ = pipe( 135 - cachedOps$, 136 - tap((result: OperationResult) => { 137 - delete data[result.operation.key]; 138 - }) 139 - ); 147 + cachedOps$ = pipe(cachedOps$, tap(invalidate)); 140 148 } 141 149 142 150 return merge([forwardedOps$, cachedOps$]);
+3 -1
packages/react-urql/src/test-utils/ssr.test.tsx
··· 148 148 }); 149 149 }); 150 150 151 - it('can rehydrate results on the client', () => { 151 + it('can rehydrate results on the client', async () => { 152 152 ssr.restoreData({ [queryOperation.key]: queryResponse }); 153 153 154 154 expect(() => { 155 155 pipe(client.executeRequestOperation(queryOperation), publish); 156 156 }).not.toThrow(); 157 + 158 + await Promise.resolve(); 157 159 158 160 const data = ssr.extractData(); 159 161 expect(Object.keys(data).length).toBe(0);