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.

(vue) - Simplify useQuery implementation (#1758)

* Replace useQuery implementation

* Fix fetching.value timings in useQuery and useSubscription

* Align useQuery and useSubscription implementations

* Add changeset

authored by

Phil Pluckthun and committed by
GitHub
a0fcea4b 891a17a0

+69 -126
+5
.changeset/strange-windows-repair.md
··· 1 + --- 2 + '@urql/vue': patch 3 + --- 4 + 5 + Refactor `useQuery` implementation to utilise the single-source implementation of `@urql/core@2.1.0`. This should improve the stability of promisified `useQuery()` calls and prevent operations from not being issued in some edge cases.
+50 -102
packages/vue-urql/src/useQuery.ts
··· 4 4 5 5 import { WatchStopHandle, Ref, ref, watchEffect, reactive, isRef } from 'vue'; 6 6 7 - import { 8 - Source, 9 - concat, 10 - switchAll, 11 - share, 12 - fromValue, 13 - makeSubject, 14 - filter, 15 - map, 16 - pipe, 17 - take, 18 - publish, 19 - onEnd, 20 - onStart, 21 - onPush, 22 - toPromise, 23 - } from 'wonka'; 7 + import { Source, map, pipe, take, subscribe, onEnd, toPromise } from 'wonka'; 24 8 25 9 import { 26 10 Client, ··· 69 53 const watchOptions = { 70 54 flush: 'pre' as const, 71 55 }; 72 - 73 - /** Wonka Operator to replay the most recent value to sinks */ 74 - function replayOne<T>(source: Source<T>): Source<T> { 75 - let cached: undefined | T; 76 - 77 - return concat([ 78 - pipe( 79 - fromValue(cached!), 80 - map(() => cached!), 81 - filter(x => x !== undefined) 82 - ), 83 - pipe( 84 - source, 85 - onPush(value => { 86 - cached = value; 87 - }), 88 - share 89 - ), 90 - ]); 91 - } 92 56 93 57 export function useQuery<T = any, V = object>( 94 58 args: UseQueryArgs<T, V> ··· 118 82 createRequest<T, V>(args.query, args.variables as V) as any 119 83 ); 120 84 121 - const source: Ref<Source<Source<any>>> = ref(null as any); 122 - const next: Ref< 123 - (query$: undefined | Source<OperationResult<T, V>>) => void 124 - > = ref(null as any); 85 + const source: Ref<Source<OperationResult> | undefined> = ref(); 125 86 126 87 stops.push( 127 88 watchEffect(() => { ··· 132 93 }, watchOptions) 133 94 ); 134 95 96 + stops.push( 97 + watchEffect(() => { 98 + source.value = !isPaused.value 99 + ? client.executeQuery<T, V>(request.value, { 100 + requestPolicy: args.requestPolicy, 101 + ...args.context, 102 + }) 103 + : undefined; 104 + }, watchOptions) 105 + ); 106 + 135 107 const state: UseQueryState<T, V> = { 136 108 data, 137 109 stale, ··· 141 113 fetching, 142 114 isPaused, 143 115 executeQuery(opts?: Partial<OperationContext>): UseQueryResponse<T, V> { 144 - next.value( 145 - client.executeQuery<T, V>(request.value, { 146 - requestPolicy: args.requestPolicy, 147 - ...args.context, 148 - ...opts, 149 - }) 150 - ); 116 + source.value = client.executeQuery<T, V>(request.value, { 117 + requestPolicy: args.requestPolicy, 118 + ...args.context, 119 + ...opts, 120 + }); 151 121 152 122 return response; 153 123 }, ··· 159 129 }, 160 130 }; 161 131 162 - const getState = () => state; 163 - 164 132 stops.push( 165 133 watchEffect( 166 134 onInvalidate => { 167 - const subject = makeSubject<Source<any>>(); 168 - source.value = pipe(subject.source, replayOne); 169 - next.value = (value: undefined | Source<any>) => { 170 - const query$ = pipe( 171 - value 172 - ? pipe( 173 - value, 174 - onStart(() => { 175 - fetching.value = true; 176 - stale.value = false; 177 - }), 178 - onPush(res => { 179 - data.value = res.data; 180 - stale.value = !!res.stale; 181 - fetching.value = false; 182 - error.value = res.error; 183 - operation.value = res.operation; 184 - extensions.value = res.extensions; 185 - }), 186 - share 187 - ) 188 - : fromValue(undefined), 189 - onEnd(() => { 190 - fetching.value = false; 191 - stale.value = false; 192 - }) 193 - ); 135 + if (source.value) { 136 + fetching.value = true; 137 + stale.value = false; 194 138 195 - subject.next(query$); 196 - }; 197 - 198 - onInvalidate( 199 - pipe(source.value, switchAll, map(getState), publish).unsubscribe 200 - ); 139 + onInvalidate( 140 + pipe( 141 + source.value, 142 + onEnd(() => { 143 + fetching.value = false; 144 + stale.value = false; 145 + }), 146 + subscribe(res => { 147 + data.value = res.data; 148 + stale.value = !!res.stale; 149 + fetching.value = false; 150 + error.value = res.error; 151 + operation.value = res.operation; 152 + extensions.value = res.extensions; 153 + }) 154 + ).unsubscribe 155 + ); 156 + } else { 157 + fetching.value = false; 158 + stale.value = false; 159 + } 201 160 }, 202 161 { 203 162 // NOTE: This part of the query pipeline is only initialised once and will need ··· 207 166 ) 208 167 ); 209 168 210 - stops.push( 211 - watchEffect(() => { 212 - next.value( 213 - !isPaused.value 214 - ? client.executeQuery<T, V>(request.value, { 215 - requestPolicy: args.requestPolicy, 216 - ...args.context, 217 - }) 218 - : undefined 219 - ); 220 - }, watchOptions) 221 - ); 222 - 223 169 const response: UseQueryResponse<T, V> = { 224 170 ...state, 225 171 then(onFulfilled, onRejected) { 226 - return pipe( 227 - source.value, 228 - switchAll, 229 - map(getState), 230 - take(1), 231 - toPromise 172 + return (source.value 173 + ? pipe( 174 + source.value, 175 + take(1), 176 + map(() => state), 177 + toPromise 178 + ) 179 + : Promise.resolve(state) 232 180 ).then(onFulfilled, onRejected); 233 181 }, 234 182 };
+14 -24
packages/vue-urql/src/useSubscription.ts
··· 1 1 /* eslint-disable react-hooks/rules-of-hooks */ 2 2 3 3 import { DocumentNode } from 'graphql'; 4 - import { Source, pipe, publish, share, onStart, onPush, onEnd } from 'wonka'; 4 + import { Source, pipe, subscribe, onEnd } from 'wonka'; 5 5 6 6 import { WatchStopHandle, Ref, ref, watchEffect, reactive, isRef } from 'vue'; 7 7 ··· 98 98 99 99 stops.push( 100 100 watchEffect(() => { 101 - if (!isPaused.value) { 102 - source.value = pipe( 103 - client.executeSubscription<T, V>(request.value, { 104 - ...args.context, 105 - }), 106 - share 107 - ); 108 - } else { 109 - source.value = undefined; 110 - } 101 + source.value = !isPaused.value 102 + ? client.executeSubscription<T, V>(request.value, { ...args.context }) 103 + : undefined; 111 104 }, watchOptions) 112 105 ); 113 106 114 107 stops.push( 115 108 watchEffect(onInvalidate => { 116 109 if (source.value) { 110 + fetching.value = true; 111 + 117 112 onInvalidate( 118 113 pipe( 119 114 source.value, 120 - onStart(() => { 121 - fetching.value = true; 122 - }), 123 115 onEnd(() => { 124 116 fetching.value = false; 125 117 }), 126 - onPush(result => { 118 + subscribe(result => { 127 119 fetching.value = true; 128 120 (data.value = 129 121 result.data !== undefined ··· 135 127 extensions.value = result.extensions; 136 128 stale.value = !!result.stale; 137 129 operation.value = result.operation; 138 - }), 139 - publish 130 + }) 140 131 ).unsubscribe 141 132 ); 133 + } else { 134 + fetching.value = false; 142 135 } 143 136 }, watchOptions) 144 137 ); ··· 154 147 executeSubscription( 155 148 opts?: Partial<OperationContext> 156 149 ): UseSubscriptionState<T, R, V> { 157 - source.value = pipe( 158 - client.executeSubscription<T, V>(request.value, { 159 - ...args.context, 160 - ...opts, 161 - }), 162 - share 163 - ); 150 + source.value = client.executeSubscription<T, V>(request.value, { 151 + ...args.context, 152 + ...opts, 153 + }); 164 154 165 155 return state; 166 156 },