mirror of https://github.com/buster-so/buster.git
type safety updates for mutation
This commit is contained in:
parent
ad02a021ac
commit
e91e0d9f86
|
@ -18,7 +18,7 @@ export const useUpdateMetricAssosciations = ({
|
||||||
}) => {
|
}) => {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites);
|
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites);
|
||||||
const forceGetFavoritesList = useUserConfigContextSelector((x) => x.forceGetFavoritesList);
|
const refreshFavoritesList = useUserConfigContextSelector((x) => x.refreshFavoritesList);
|
||||||
const removeItemFromIndividualDashboard = useBusterDashboardContextSelector(
|
const removeItemFromIndividualDashboard = useBusterDashboardContextSelector(
|
||||||
(state) => state.removeItemFromIndividualDashboard
|
(state) => state.removeItemFromIndividualDashboard
|
||||||
);
|
);
|
||||||
|
@ -108,7 +108,7 @@ export const useUpdateMetricAssosciations = ({
|
||||||
|
|
||||||
if (addToPromises.length) await Promise.all(addToPromises);
|
if (addToPromises.length) await Promise.all(addToPromises);
|
||||||
if (collectionIsInFavorites) {
|
if (collectionIsInFavorites) {
|
||||||
await forceGetFavoritesList();
|
await refreshFavoritesList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -205,7 +205,7 @@ export const useUpdateMetricAssosciations = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (collectionIsInFavorites && ignoreFavoriteUpdates !== true) {
|
if (collectionIsInFavorites && ignoreFavoriteUpdates !== true) {
|
||||||
await forceGetFavoritesList();
|
await refreshFavoritesList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,39 +1,31 @@
|
||||||
import React, { useRef } from 'react';
|
|
||||||
import { useBusterWebSocket } from '../BusterWebSocket';
|
import { useBusterWebSocket } from '../BusterWebSocket';
|
||||||
import { useMemoizedFn, useMount } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import type { BusterUserFavorite } from '@/api/asset_interfaces';
|
import { BusterUserFavorite, ShareAssetType } from '@/api/asset_interfaces';
|
||||||
import { ShareAssetType } from '@/api/asset_interfaces';
|
import { createQueryKey, useSocketQueryEmitOn } from '@/hooks';
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
|
||||||
export const useFavoriteProvider = () => {
|
export const useFavoriteProvider = () => {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
const useMountedUserFavorites = useRef(false);
|
const queryClient = useQueryClient();
|
||||||
const [userFavorites, setUserFavorites] = React.useState<BusterUserFavorite[]>([]);
|
|
||||||
|
|
||||||
const _onSetInitialFavoritesList = useMemoizedFn((favorites: BusterUserFavorite[]) => {
|
const favoritesQueryKey = createQueryKey(
|
||||||
setUserFavorites(favorites);
|
{ route: '/users/favorites/list:listFavorites' },
|
||||||
});
|
{ route: '/users/favorites/list', payload: {} }
|
||||||
|
);
|
||||||
|
|
||||||
const forceGetFavoritesList = useMemoizedFn(() => {
|
const { data: userFavorites, refetch: refreshFavoritesList } = useSocketQueryEmitOn(
|
||||||
useMountedUserFavorites.current = false;
|
{ route: '/users/favorites/list', payload: {} },
|
||||||
busterSocket.off({
|
{ route: '/users/favorites/list:listFavorites' }
|
||||||
route: '/users/favorites/list:listFavorites',
|
);
|
||||||
callback: _onSetInitialFavoritesList
|
|
||||||
});
|
|
||||||
return _onGetFavoritesList();
|
|
||||||
});
|
|
||||||
|
|
||||||
const _onGetFavoritesList = useMemoizedFn(() => {
|
const setUserFavorites = useMemoizedFn(
|
||||||
if (useMountedUserFavorites.current) return;
|
(updater: (v: BusterUserFavorite[]) => BusterUserFavorite[]) => {
|
||||||
useMountedUserFavorites.current = true;
|
queryClient.setQueryData(favoritesQueryKey, (v: BusterUserFavorite[] | undefined) => {
|
||||||
busterSocket.emit({
|
return updater(v || []);
|
||||||
route: '/users/favorites/list',
|
|
||||||
payload: {}
|
|
||||||
});
|
|
||||||
busterSocket.on({
|
|
||||||
route: '/users/favorites/list:listFavorites',
|
|
||||||
callback: _onSetInitialFavoritesList
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const addItemToFavorite = useMemoizedFn(
|
const addItemToFavorite = useMemoizedFn(
|
||||||
async ({
|
async ({
|
||||||
|
@ -48,77 +40,81 @@ export const useFavoriteProvider = () => {
|
||||||
}) => {
|
}) => {
|
||||||
setUserFavorites((v) => [{ id, type: asset_type, name }, ...v]);
|
setUserFavorites((v) => [{ id, type: asset_type, name }, ...v]);
|
||||||
|
|
||||||
await busterSocket.emitAndOnce({
|
// busterSocket.emit({
|
||||||
emitEvent: {
|
// route: '/users/favorites/post',
|
||||||
route: '/users/favorites/post',
|
// payload: {
|
||||||
payload: {
|
// id,
|
||||||
id,
|
// asset_type
|
||||||
asset_type
|
// }
|
||||||
}
|
// });
|
||||||
},
|
|
||||||
responseEvent: {
|
// await busterSocket.emitAndOnce({
|
||||||
route: '/users/favorites/post:createFavorite',
|
// emitEvent: {
|
||||||
callback: _onSetInitialFavoritesList
|
// route: '/users/favorites/post',
|
||||||
}
|
// payload: {
|
||||||
});
|
// id,
|
||||||
|
// asset_type
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// responseEvent: {
|
||||||
|
// route: '/users/favorites/post:createFavorite',
|
||||||
|
// callback: _onSetInitialFavoritesList
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeItemFromFavorite = useMemoizedFn(
|
const removeItemFromFavorite = useMemoizedFn(
|
||||||
async ({ id, asset_type }: { id: string; asset_type: ShareAssetType }) => {
|
async ({ id, asset_type }: { id: string; asset_type: ShareAssetType }) => {
|
||||||
setUserFavorites(userFavorites.filter((f) => f.id !== id));
|
// setUserFavorites(userFavorites.filter((f) => f.id !== id));
|
||||||
await busterSocket.emitAndOnce({
|
// await busterSocket.emitAndOnce({
|
||||||
emitEvent: {
|
// emitEvent: {
|
||||||
route: '/users/favorites/delete',
|
// route: '/users/favorites/delete',
|
||||||
payload: {
|
// payload: {
|
||||||
id,
|
// id,
|
||||||
asset_type
|
// asset_type
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
responseEvent: {
|
// responseEvent: {
|
||||||
route: '/users/favorites/post:createFavorite',
|
// route: '/users/favorites/post:createFavorite',
|
||||||
callback: _onSetInitialFavoritesList
|
// callback: _onSetInitialFavoritesList
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const reorderFavorites = useMemoizedFn(async (favorites: string[]) => {
|
const reorderFavorites = useMemoizedFn(async (favorites: string[]) => {
|
||||||
requestAnimationFrame(() => {
|
// requestAnimationFrame(() => {
|
||||||
setUserFavorites((v) => {
|
// setUserFavorites((v) => {
|
||||||
return favorites.map((id, index) => {
|
// return favorites.map((id, index) => {
|
||||||
let favorite = v.find((f) => f.id === id || f.collection_id === id)!;
|
// let favorite = v.find((f) => f.id === id || f.collection_id === id)!;
|
||||||
return { ...favorite, index };
|
// return { ...favorite, index };
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
await busterSocket.emitAndOnce({
|
// await busterSocket.emitAndOnce({
|
||||||
emitEvent: {
|
// emitEvent: {
|
||||||
route: '/users/favorites/update',
|
// route: '/users/favorites/update',
|
||||||
payload: {
|
// payload: {
|
||||||
favorites
|
// favorites
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
responseEvent: {
|
// responseEvent: {
|
||||||
route: '/users/favorites/update:updateFavorite',
|
// route: '/users/favorites/update:updateFavorite',
|
||||||
callback: _onSetInitialFavoritesList
|
// callback: _onSetInitialFavoritesList
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
const bulkEditFavorites = useMemoizedFn(async (favorites: string[]) => {
|
const bulkEditFavorites = useMemoizedFn(async (favorites: string[]) => {
|
||||||
return reorderFavorites(favorites);
|
return reorderFavorites(favorites);
|
||||||
});
|
});
|
||||||
|
|
||||||
useMount(async () => {
|
|
||||||
_onGetFavoritesList();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bulkEditFavorites,
|
bulkEditFavorites,
|
||||||
forceGetFavoritesList,
|
refreshFavoritesList,
|
||||||
reorderFavorites,
|
reorderFavorites,
|
||||||
userFavorites,
|
userFavorites: userFavorites || [],
|
||||||
addItemToFavorite,
|
addItemToFavorite,
|
||||||
removeItemFromFavorite
|
removeItemFromFavorite
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export * from './react';
|
export * from './react';
|
||||||
export * from './dom';
|
export * from './dom';
|
||||||
export * from './useDebounceSearch';
|
export * from './useDebounceSearch';
|
||||||
export * from './useBusterWebSocketQuery';
|
export * from './useSocketQuery';
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './useBusterWebSocketQuery';
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { BusterSocketRequest, BusterSocketResponseRoute } from '@/api/buster_socket';
|
||||||
|
import { BusterSocketResponseConfig } from './types';
|
||||||
|
import { QueryKey } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
export const createQueryKey: <TRoute extends BusterSocketResponseRoute>(
|
||||||
|
socketResponse: BusterSocketResponseConfig<TRoute>,
|
||||||
|
socketRequest?: BusterSocketRequest
|
||||||
|
) => QueryKey = (socketResponse, socketRequest) => {
|
||||||
|
if (socketRequest) return [socketResponse.route, socketRequest.route, socketRequest.payload];
|
||||||
|
return [socketResponse.route];
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { createQueryKey } from './helpers';
|
||||||
|
import { BusterSocketResponseConfig } from './types';
|
||||||
|
|
||||||
|
export * from './useSocketQueryEmitAndOnce';
|
||||||
|
export * from './useSocketQueryEmitOn';
|
||||||
|
export * from './useSocketQueryOn';
|
||||||
|
|
||||||
|
export { createQueryKey, type BusterSocketResponseConfig };
|
|
@ -11,18 +11,24 @@ import type {
|
||||||
BusterSocketResponseConfig
|
BusterSocketResponseConfig
|
||||||
} from './types';
|
} from './types';
|
||||||
import { useCreateReactQuery } from '@/api/createReactQuery';
|
import { useCreateReactQuery } from '@/api/createReactQuery';
|
||||||
|
import { createQueryKey } from './helpers';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export function useBusterWebSocketQuery<TRoute extends BusterSocketResponseRoute, TError = unknown>(
|
export function useSocketQueryEmitAndOnce<
|
||||||
queryKey: QueryKey,
|
TRoute extends BusterSocketResponseRoute,
|
||||||
|
TError = unknown
|
||||||
|
>(
|
||||||
socketRequest: BusterSocketRequest,
|
socketRequest: BusterSocketRequest,
|
||||||
socketResponse: BusterSocketResponseConfig<TRoute>,
|
socketResponse: BusterSocketResponseConfig<TRoute>,
|
||||||
options?: Omit<
|
options?: Partial<Omit<UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>, 'queryFn'>>
|
||||||
UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>,
|
|
||||||
'queryKey' | 'queryFn'
|
|
||||||
>
|
|
||||||
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> {
|
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
|
|
||||||
|
const queryKey = useMemo(
|
||||||
|
() => options?.queryKey || createQueryKey(socketResponse, socketRequest),
|
||||||
|
[options?.queryKey, socketResponse?.route, socketRequest?.route]
|
||||||
|
);
|
||||||
|
|
||||||
const queryFn = async (): Promise<InferBusterSocketResponseData<TRoute>> => {
|
const queryFn = async (): Promise<InferBusterSocketResponseData<TRoute>> => {
|
||||||
try {
|
try {
|
||||||
const result = await busterSocket.emitAndOnce({
|
const result = await busterSocket.emitAndOnce({
|
||||||
|
@ -44,15 +50,8 @@ export function useBusterWebSocketQuery<TRoute extends BusterSocketResponseRoute
|
||||||
queryKey,
|
queryKey,
|
||||||
queryFn,
|
queryFn,
|
||||||
isUseSession: false,
|
isUseSession: false,
|
||||||
|
refetchOnMount: false,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
options
|
options
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example usage with automatic type inference
|
|
||||||
const ExampleUsage = () => {
|
|
||||||
const { data, isLoading, error } = useBusterWebSocketQuery(
|
|
||||||
['chats', 'get', '123'],
|
|
||||||
{ route: '/chats/get', payload: { id: '123' } },
|
|
||||||
{ route: '/chats/get:getChat' }
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import {
|
||||||
|
BusterSocketRequest,
|
||||||
|
BusterSocketResponse,
|
||||||
|
BusterSocketResponseRoute
|
||||||
|
} from '@/api/buster_socket';
|
||||||
|
import { useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import {
|
||||||
|
BusterSocketResponseConfig,
|
||||||
|
InferBusterSocketResponseData,
|
||||||
|
UseBusterSocketQueryResult
|
||||||
|
} from './types';
|
||||||
|
import { useSockeQueryOn } from './useSocketQueryOn';
|
||||||
|
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
||||||
|
import { useMemoizedFn, useMount } from 'ahooks';
|
||||||
|
import { createQueryKey } from './helpers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook that emits a socket request on mount and listens for responses.
|
||||||
|
*
|
||||||
|
* @template TRoute - The type of socket response route
|
||||||
|
* @template TError - The type of error that can occur
|
||||||
|
*
|
||||||
|
* @param socketRequest - The socket request to emit
|
||||||
|
* @param socketResponse - Configuration for the socket response including route and error handler
|
||||||
|
* @param options - Additional options for the React Query hook
|
||||||
|
*
|
||||||
|
* @returns A React Query result containing the response data and status
|
||||||
|
*/
|
||||||
|
export const useSocketQueryEmitOn = <TRoute extends BusterSocketResponseRoute, TError = unknown>(
|
||||||
|
socketRequest: BusterSocketRequest,
|
||||||
|
socketResponse: BusterSocketResponseConfig<TRoute>,
|
||||||
|
options?: Omit<
|
||||||
|
UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>,
|
||||||
|
'queryKey' | 'queryFn'
|
||||||
|
>
|
||||||
|
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> => {
|
||||||
|
const busterSocket = useBusterWebSocket();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const queryKey = createQueryKey(socketResponse, socketRequest);
|
||||||
|
|
||||||
|
const emitEvent = useMemoizedFn(async () => {
|
||||||
|
const res = await busterSocket.emitAndOnce({
|
||||||
|
emitEvent: socketRequest,
|
||||||
|
responseEvent: {
|
||||||
|
...socketResponse,
|
||||||
|
callback: (d: unknown) => d
|
||||||
|
} as BusterSocketResponse
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}) as () => Promise<InferBusterSocketResponseData<TRoute>>;
|
||||||
|
|
||||||
|
useMount(() => {
|
||||||
|
emitEvent();
|
||||||
|
});
|
||||||
|
|
||||||
|
return useSockeQueryOn(socketResponse, {
|
||||||
|
...options,
|
||||||
|
queryKey,
|
||||||
|
queryFn: emitEvent
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,130 @@
|
||||||
|
import {
|
||||||
|
BusterSocketRequest,
|
||||||
|
BusterSocketResponse,
|
||||||
|
BusterSocketResponseRoute
|
||||||
|
} from '@/api/buster_socket';
|
||||||
|
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
import { BusterSocketResponseConfig, InferBusterSocketResponseData } from './types';
|
||||||
|
import { ShareAssetType } from '@/api/asset_interfaces';
|
||||||
|
import { createQueryKey } from './helpers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook that creates a mutation for emitting socket requests and handling responses.
|
||||||
|
*
|
||||||
|
* @template TRoute - The type of socket response route
|
||||||
|
* @template TData - The type of data returned by the socket response
|
||||||
|
* @template TVariables - The type of variables passed to the mutation function
|
||||||
|
* @template TError - The type of error that can occur
|
||||||
|
*
|
||||||
|
* @param socketRequest - The base socket request to emit (variables will be merged with this)
|
||||||
|
* @param socketResponse - Configuration for the socket response including route and error handler
|
||||||
|
* @param options - Additional options for the React Query mutation hook
|
||||||
|
*
|
||||||
|
* @returns A React Query mutation result for handling socket requests
|
||||||
|
*/
|
||||||
|
export const useSocketQueryMutation = <
|
||||||
|
TRoute extends BusterSocketResponseRoute,
|
||||||
|
TVariables = void,
|
||||||
|
TError = unknown
|
||||||
|
>(
|
||||||
|
socketRequest: BusterSocketRequest,
|
||||||
|
socketResponse: BusterSocketResponseConfig<TRoute> & {
|
||||||
|
callback?: (d: unknown) => InferBusterSocketResponseData<TRoute>;
|
||||||
|
},
|
||||||
|
optionsProps?: Omit<
|
||||||
|
UseMutationOptions<InferBusterSocketResponseData<TRoute>, TError, TVariables>,
|
||||||
|
'mutationFn'
|
||||||
|
> & {
|
||||||
|
preSetQueryData?: (
|
||||||
|
d: InferBusterSocketResponseData<TRoute> | undefined,
|
||||||
|
variables: TVariables
|
||||||
|
) => InferBusterSocketResponseData<TRoute>;
|
||||||
|
queryDataStrategy?: 'replace' | 'append' | 'prepend' | 'merge' | 'ignore';
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const busterSocket = useBusterWebSocket();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { preSetQueryData, queryDataStrategy = 'ignore', ...options } = optionsProps || {};
|
||||||
|
|
||||||
|
const mutationFn = useMemoizedFn(async (variables: TVariables) => {
|
||||||
|
const queryKey = createQueryKey(socketResponse, socketRequest);
|
||||||
|
|
||||||
|
if (preSetQueryData) {
|
||||||
|
await queryClient.setQueryData<InferBusterSocketResponseData<TRoute>>(queryKey, (d) => {
|
||||||
|
return preSetQueryData(d, variables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await busterSocket.emitAndOnce({
|
||||||
|
emitEvent: socketRequest,
|
||||||
|
responseEvent: {
|
||||||
|
...socketResponse,
|
||||||
|
callback: (d: unknown) => {
|
||||||
|
if (socketResponse.callback) {
|
||||||
|
socketResponse.callback(d);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} as BusterSocketResponse
|
||||||
|
});
|
||||||
|
|
||||||
|
if (queryDataStrategy === 'replace') {
|
||||||
|
await queryClient.setQueryData<InferBusterSocketResponseData<TRoute>>(queryKey, () => {
|
||||||
|
return res as InferBusterSocketResponseData<TRoute>;
|
||||||
|
});
|
||||||
|
} else if (queryDataStrategy === 'append') {
|
||||||
|
await queryClient.setQueryData<InferBusterSocketResponseData<TRoute>[]>(queryKey, (d) => {
|
||||||
|
return [...(Array.isArray(d) ? d : []), res as InferBusterSocketResponseData<TRoute>];
|
||||||
|
});
|
||||||
|
} else if (queryDataStrategy === 'prepend') {
|
||||||
|
await queryClient.setQueryData<InferBusterSocketResponseData<TRoute>[]>(queryKey, (d) => {
|
||||||
|
return [res as InferBusterSocketResponseData<TRoute>, ...(Array.isArray(d) ? d : [])];
|
||||||
|
});
|
||||||
|
} else if (queryDataStrategy === 'merge') {
|
||||||
|
await queryClient.setQueryData<Record<string, InferBusterSocketResponseData<TRoute>>>(
|
||||||
|
queryKey,
|
||||||
|
(d) => {
|
||||||
|
if (typeof res === 'object' && res !== null && 'id' in res) {
|
||||||
|
const typedRes = res as InferBusterSocketResponseData<TRoute> & { id: string };
|
||||||
|
return {
|
||||||
|
...(d || {}),
|
||||||
|
[typedRes.id]: typedRes
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
console.warn('response is not an object with an id', res);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res as InferBusterSocketResponseData<TRoute>;
|
||||||
|
});
|
||||||
|
|
||||||
|
return useMutation<InferBusterSocketResponseData<TRoute>, TError, TVariables>({
|
||||||
|
...options,
|
||||||
|
mutationFn
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const Example = () => {
|
||||||
|
const { mutate, data, ...rest } = useSocketQueryMutation(
|
||||||
|
{
|
||||||
|
route: '/users/favorites/post',
|
||||||
|
payload: {
|
||||||
|
id: '1',
|
||||||
|
asset_type: ShareAssetType.DASHBOARD
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
route: '/users/favorites/post:createFavorite'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
preSetQueryData: (d) => {
|
||||||
|
return d || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,7 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { QueryKey, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { QueryKey, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
import type { BusterSocketResponse, BusterSocketResponseRoute } from '@/api/buster_socket';
|
import type {
|
||||||
|
BusterSocketRequest,
|
||||||
|
BusterSocketResponse,
|
||||||
|
BusterSocketResponseRoute
|
||||||
|
} from '@/api/buster_socket';
|
||||||
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
import { useBusterWebSocket } from '@/context/BusterWebSocket';
|
||||||
import type {
|
import type {
|
||||||
UseBusterSocketQueryResult,
|
UseBusterSocketQueryResult,
|
||||||
|
@ -9,32 +13,34 @@ import type {
|
||||||
BusterSocketResponseConfig
|
BusterSocketResponseConfig
|
||||||
} from './types';
|
} from './types';
|
||||||
import { useMount } from 'ahooks';
|
import { useMount } from 'ahooks';
|
||||||
|
import { createQueryKey } from './helpers';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export const useBusterWebSocketOn = <TRoute extends BusterSocketResponseRoute, TError = unknown>(
|
export const useSockeQueryOn = <TRoute extends BusterSocketResponseRoute, TError = unknown>(
|
||||||
queryKey: QueryKey,
|
socketResponse: BusterSocketResponseConfig<TRoute>,
|
||||||
socketResponse: BusterSocketResponseConfig<TRoute>
|
options?: Partial<UseQueryOptions<InferBusterSocketResponseData<TRoute>, TError>>
|
||||||
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> => {
|
): UseBusterSocketQueryResult<InferBusterSocketResponseData<TRoute>, TError> => {
|
||||||
const busterSocket = useBusterWebSocket();
|
const busterSocket = useBusterWebSocket();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const queryKey = useMemo(
|
||||||
|
() => options?.queryKey || createQueryKey(socketResponse),
|
||||||
|
[options?.queryKey, socketResponse?.route]
|
||||||
|
);
|
||||||
|
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
busterSocket.on({
|
busterSocket.on({
|
||||||
route: socketResponse.route,
|
route: socketResponse.route,
|
||||||
onError: socketResponse.onError,
|
onError: socketResponse.onError,
|
||||||
callback: (d: unknown) => {
|
callback: (d: unknown) => {
|
||||||
queryClient.setQueryData(queryKey, d as InferBusterSocketResponseData<TRoute>);
|
queryClient.setQueryData(queryKey, d as InferBusterSocketResponseData<TRoute>);
|
||||||
queryClient.invalidateQueries({ queryKey });
|
|
||||||
}
|
}
|
||||||
} as BusterSocketResponse);
|
} as BusterSocketResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey
|
queryKey,
|
||||||
});
|
...options,
|
||||||
};
|
enabled: false
|
||||||
|
|
||||||
const ExampleUsage = () => {
|
|
||||||
const { data, isFetched } = useBusterWebSocketOn(['chats', 'get', '123'], {
|
|
||||||
route: '/chats/get:getChat'
|
|
||||||
});
|
});
|
||||||
};
|
};
|
Loading…
Reference in New Issue