Skip to content
This repository was archived by the owner on Nov 23, 2024. It is now read-only.

Commit 4771d0a

Browse files
committed
Replace ref with setState, batch updates
1 parent 53ed749 commit 4771d0a

File tree

2 files changed

+40
-28
lines changed

2 files changed

+40
-28
lines changed

src/react-hooks/buildHooks.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export type UseLazyQuery<D extends QueryDefinition<any, any, any, any>> = <R = U
6060

6161
export type UseLazyQuerySubscription<D extends QueryDefinition<any, any, any, any>> = (
6262
options?: SubscriptionOptions
63-
) => [(args: QueryArgFrom<D>) => void, undefined | React.MutableRefObject<QueryActionCreatorResult<any>>['current']];
63+
) => [(args: QueryArgFrom<D>) => void, undefined | QueryActionCreatorResult<any>];
6464

6565
export type QueryStateSelector<R, D extends QueryDefinition<any, any, any, any>> = (
6666
state: QueryResultSelectorResult<D>,
@@ -252,57 +252,62 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
252252
refetchOnFocus,
253253
pollingInterval = 0,
254254
} = {}) => {
255-
const forceUpdate = useReducer(() => ({}), {})[1];
256255
const { initiate } = api.endpoints[name] as ApiEndpointQuery<
257256
QueryDefinition<any, any, any, any, any>,
258257
Definitions
259258
>;
260259
const dispatch = useDispatch<ThunkDispatch<any, any, AnyAction>>();
261260

262-
const promiseRef = useRef<QueryActionCreatorResult<any>>();
263-
const lastPromise = promiseRef.current;
261+
const [promiseRef, setPromiseRef] = useState<QueryActionCreatorResult<any>>();
262+
const unmountRef = useRef<QueryActionCreatorResult<any> | undefined>();
264263

265264
useEffect(() => {
266265
const subscriptionOptions = {
267266
refetchOnReconnect,
268267
refetchOnFocus,
269268
pollingInterval,
270269
};
271-
if (lastPromise && !shallowEqual(subscriptionOptions, lastPromise.subscriptionOptions)) {
272-
lastPromise?.updateSubscriptionOptions(subscriptionOptions);
273-
lastPromise.subscriptionOptions = subscriptionOptions;
270+
if (promiseRef && !shallowEqual(subscriptionOptions, promiseRef.subscriptionOptions)) {
271+
promiseRef?.updateSubscriptionOptions(subscriptionOptions);
272+
setPromiseRef((prev) => ({ ...prev!, subscriptionOptions }));
274273
}
275-
}, [lastPromise, refetchOnFocus, refetchOnReconnect, pollingInterval]);
274+
}, [promiseRef, refetchOnFocus, refetchOnReconnect, pollingInterval]);
275+
276+
useEffect(() => {
277+
unmountRef.current = promiseRef;
278+
}, [promiseRef]);
276279

277280
useEffect(() => {
278281
return () => {
279-
promiseRef.current?.unsubscribe();
280-
promiseRef.current = undefined;
282+
unmountRef?.current?.unsubscribe();
281283
};
282284
}, []);
283285

284286
const trigger = useCallback(
285287
function (arg: any) {
286-
lastPromise?.unsubscribe();
287-
288-
const subscriptionOptions = {
289-
refetchOnReconnect,
290-
refetchOnFocus,
291-
pollingInterval,
292-
};
293-
294-
promiseRef.current = dispatch(
295-
initiate(arg, {
296-
subscriptionOptions,
297-
forceRefetch: true,
298-
})
299-
);
300-
forceUpdate();
288+
batch(() => {
289+
promiseRef?.unsubscribe();
290+
291+
const subscriptionOptions = {
292+
refetchOnReconnect,
293+
refetchOnFocus,
294+
pollingInterval,
295+
};
296+
297+
const promise = dispatch(
298+
initiate(arg, {
299+
subscriptionOptions,
300+
forceRefetch: true,
301+
})
302+
);
303+
304+
setPromiseRef(promise);
305+
});
301306
},
302-
[dispatch, initiate, lastPromise, pollingInterval, refetchOnFocus, refetchOnReconnect]
307+
[dispatch, initiate, promiseRef, pollingInterval, refetchOnFocus, refetchOnReconnect]
303308
);
304309

305-
return useMemo(() => [trigger, lastPromise], [trigger, lastPromise]);
310+
return useMemo(() => [trigger, promiseRef], [trigger, promiseRef]);
306311
};
307312

308313
const useQueryState: UseQueryState<any> = (

test/buildHooks.test.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ describe('hooks tests', () => {
488488
);
489489
}
490490

491-
render(<User />, { wrapper: storeRef.wrapper });
491+
const { unmount } = render(<User />, { wrapper: storeRef.wrapper });
492492

493493
await waitFor(() => expect(screen.getByTestId('isUninitialized').textContent).toBe('true'));
494494
await waitFor(() => expect(data).toBeUndefined());
@@ -523,6 +523,13 @@ describe('hooks tests', () => {
523523
expect(storeRef.store.getState().actions.filter(api.internalActions.unsubscribeQueryResult.match)).toHaveLength(
524524
3
525525
);
526+
527+
unmount();
528+
529+
// We unsubscribe after the component unmounts
530+
expect(storeRef.store.getState().actions.filter(api.internalActions.unsubscribeQueryResult.match)).toHaveLength(
531+
4
532+
);
526533
});
527534
});
528535

0 commit comments

Comments
 (0)