Skip to content

Instantly share code, notes, and snippets.

@isocroft
Last active March 17, 2024 13:30
Show Gist options
  • Save isocroft/2ee61c2b197afb25a93f7f18ecbb9f4d to your computer and use it in GitHub Desktop.
Save isocroft/2ee61c2b197afb25a93f7f18ecbb9f4d to your computer and use it in GitHub Desktop.
This is a custom hook that allows you to utilize a simple strategy pattern to select <@tanstack/react-query> `useQuery` custom hooks within a single component
import React, { useContext, useMemo } from "react";
import type { UseQueryResult } from "react-query";
type ReactQueryFetchStatus = "idle" | "loading" | "error" | "success";
export type UseQueryPackedUnion = "status" | "data";
/*
type ReactQueryFetchHook<F extends Array<unknown>, Q = any, P = any> = (...hookArguments: [...F, P?]) => UseQueryResult<Q> | Pick<UseQueryResult<Q>, UseQueryPackedUnion>
const queriesMap: Record<"getTodos", ReactQueryFetchHook<[string]>> = {
"getTodos": () => ({})
}
*/
const queriesMapContext = React.createContext({
})
export function QueriesMapProvider({ children, map }: { children: React.ReactNode, map: Record<string, Function> }) {
const mapped = useMemo(() => map, [...Oject.keys(map)]);
return <QueriesMapContext.Provider value={mapped}>
{children}
</QueriesMapContext.Provider>
}
export function useQueryFromMap<T, V extends Record<string, Function>, A extends Array<unknown>, E = unknown>(key: keyof typeof queriesMap, useQueryArgs?: A) {
const queriesMap = useContext(QueriesMapContext) as V;
const fetchHook: Function = key in queriesMap ? queriesMap[key] : (() => ({ }));
const result: Pick<UseQueryResult<T, E>, UseQueryPackedUnion> = fetchHook(...(useQueryArgs || []));
return result;
}
@isocroft
Copy link
Author

App.tsx

import React from "react";
import type { UseQueryResult } from "react-query";
import type { UseQueryPackedUnion } from "./useQueryFromMap.tsx";
import { useQueryFromMap } from "./useQueryFromMap.tsx";

const useGetTodos = (): Pick<UseQueryResult<{ todos: string[] }>, UseQueryPackedUnion>  => ({ data: { todos: [] }, status: "idle" })
const useGetStats = (): Pick<UseQueryResult<{ stats: number[] }>, UseQueryPackedUnion> => ({ data: { stats: [] }, status: "idle" })

export const queriesMap = {
  "getTodos": useGetTodos,
  "getStats": useGetStats,
};

export default function App (query: keyof typeof queriesMap) {
  const { data } = useQueryFromMap<unknown, typeof queriesMap>(query)
  return (<ul>
   {data.map((datum, index) => {
     return <li key={String(index)}>{datum}</li>
   }}
  </ul>);
}

index.ts

import React from "react";
import ReactDOM from "react-dom";
import { QueriesMapProvider } from "./useQueryFromMap.tsx";

import App, { queriesMap } from "./App.tsx";

function Root() {
  return (
      <QueriesMapProvider map={queriesMap}>
         <App />
      </QueriesMapProvider>
  );
}

ReactDOM.render(<Root />, document.getElementById('root'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment