{"id":16903228,"url":"https://github.com/dpup/react-query-grpc-gateway","last_synced_at":"2025-04-11T14:24:06.727Z","repository":{"id":238594625,"uuid":"796933822","full_name":"dpup/react-query-grpc-gateway","owner":"dpup","description":"React hook for querying gRPC Gateway endpoints using Tanstack Query","archived":false,"fork":false,"pushed_at":"2024-11-06T23:20:41.000Z","size":110,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T10:37:45.312Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dpup.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-06T22:26:56.000Z","updated_at":"2024-12-18T17:43:46.000Z","dependencies_parsed_at":"2024-05-14T01:27:49.922Z","dependency_job_id":"049eeb42-fff2-4051-b942-830d6bfa5b26","html_url":"https://github.com/dpup/react-query-grpc-gateway","commit_stats":null,"previous_names":["dpup/react-query-grpc-gateway"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Freact-query-grpc-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Freact-query-grpc-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Freact-query-grpc-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Freact-query-grpc-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpup","download_url":"https://codeload.github.com/dpup/react-query-grpc-gateway/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248418474,"owners_count":21100191,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T18:11:55.969Z","updated_at":"2025-04-11T14:24:06.706Z","avatar_url":"https://github.com/dpup.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Query for gRPC Gateway\n\nA custom hook using [TanStack Query](https://github.com/tanstack/query) that\nmakes calling gRPC Gateway methods simpler. This hook is intended to be used\nwith [generated TypeScript clients](https://github.com/dpup/protoc-gen-grpc-gateway-ts).\n\n## Installation\n\n```sh\n# pnpm\npnpm add react-query-grpc-gateway\n\n# yarn\nyarn add react-query-grpc-gateway\n\n# npm\nnpm install react-query-grpc-gateway\n```\n\n## Usage\n\n- [Queries](#queries)\n- [Mutations](#mutations)\n- [Managing side effects](#side-effects)\n- [Advanced usage](#advanced-usage)\n\n### Queries\n\n`useServiceQuery` is a drop in replacement for `useQuery` that allows for the propagation of request configuration through the context.\n\nAssuming you have a proto definition for a `UserService` with a `GetUser`\nmethod, then your original code might look as follows:\n\n#### Without `useServiceQuery`\n\n```ts\nconst UserProfilePage ({ userID }) =\u003e {\n  const result = useQuery({\n    queryKey: ['user', userID],\n    queryFn: () =\u003e getUser({ id: userID }, {\n      pathPrefix: API_HOST,\n      credentials: 'include',\n      headers: {\n        'X-CSRF-Protection': 1\n      }\n    }),\n  });\n  if (result.isLoading) return \u003cLoadingScreen /\u003e;\n  else if (result.isError) return \u003cErrorPage error={result.error} /\u003e;\n  else \u003cUserProfile user={result.data} /\u003e\n}\n```\n\n#### With `useServiceQuery`\n\nIn your root App component update it to include a `ServiceContext.Provider` and\nconfigure any global configuration for making requests. This can include headers,\nauthentication tokens, and any properties that get forwarded to the standard\n`fetch` library.\n\n```ts\nconst AppProviders = ({ children }) =\u003e {\n  const requestOptions = {\n    pathPrefix: API_HOST,\n    credentials: 'include',\n    headers: {\n      'X-CSRF-Protection': 1,\n    },\n  };\n  return (\n    \u003cQueryClientProvider client={queryClient}\u003e\n      \u003cServiceContext.Provider value={requestOptions}\u003e{children}\u003c/ServiceContext.Provider\u003e\n    \u003c/QueryClientProvider\u003e\n  );\n};\n```\n\nThen in your component that's loading data, update it to use `useServiceQuery`:\n\n```ts\nconst UserProfilePage ({ userID }) =\u003e {\n  const result = useServiceQuery(getUser, { id: userID });\n  if (result.isLoading) return \u003cLoadingScreen /\u003e;\n  else if (result.isError) return \u003cErrorPage error={result.error} /\u003e;\n  else \u003cUserProfile user={result.data} /\u003e\n}\n```\n\nThe arguments for `useServiceQuery` are:\n\n1. The service method.\n2. The request object.\n3. Standard `useQuery` options with the addition of an `onError` handler.\n\n`onError` can be used to customize error handling behavior at the request level,\nfor example, don't even show React Query that a 401 occurred.\n\n### Mutations\n\n`useServiceMutation` is a drop in replacement for `useMutation`.\n\n```ts\nconst mutation = useServiceMutation(UserService.UpdateUser);\nmutation.mutate({ id: userID, name: newName });\n```\n\n### Side Effects\n\nReact Query's `useMutation` accepts handlers for `onMutate`, `onSuccess`,\n`onError`, and `onSettled`. When executing a query you often find yourself\nneeding to manage the data from other queries, which can get cumbersome.\n\nThe `sideEffect` function creates mutation handlers that make it easy to manage\nsuch dependent queries.\n\nIn the following example calling `updateUser` will optimistically update the\ndata associated with `getUser` and will invalidate the results of `getUserList`:\n\n```ts\nexport const useUpdateUser = () =\u003e {\n  return useServiceMutation(updateUser, {\n    ...chainSideEffects(\n      sideEffect(getUser, {\n        mapKey: ({ workspaceId, userId }) =\u003e ({ workspaceId, userId }),\n        patchFn,\n        updateFn,\n      }),\n      sideEffect(getUserList, {\n        mapKey: (_update) =\u003e null,\n        invalidate: true,\n      }),\n    ),\n  });\n};\n```\n\nIn the above example `updateUser` is considered the source query. `getUser` and\n`getUserList` are target queries. For the target query, the following things\nhappen:\n\n1. Any pending queries are cancelled.\n2. If `patchFn` is provided, cached data is optimistically updated in place `onMutate`.\n3. If the request succeeds and `updateFn` is provided, cached data is updated accordingly.\n4. If the request succeeds and `invalidate` is specified, the query is invalidated.\n5. If the request errors, then any optimistic updates are reverted.\n\nThe options for `sideEffect` are:\n\n#### `mapKey?: (update: TSourceReq) =\u003e TTargetReq;`\n\nMaps the query key for the source request to an equivalent target request that\nshould be invalidated.\n\nIn the above example, `getUser` for a specific workspace \u0026 user is matched,\nwhile for `getUserList` all cached results are matched.\n\n#### `patchFn?: (oldData: TTargetResp, update: TSourceReq) =\u003e TTargetResp;`\n\nA function that is used to optimistically update the stored value for a target\nquery based on the source request. The default `patchFn` copies all fields from\nthe update onto the original object.\n\n#### `updateFn?: (oldData: TTargetResp, result: TSourceResp) =\u003e TTargetResp;`\n\nA function that is used to process the source queries response and update the\ntarget query accordingly. The default `updateFn` replaces the target response\nwith the source response. This only works if the queries share the same\ninterface, as in the above example which assumes that `updateUser` returns the\nsame data as `getUser`.\n\n#### `invalidate?: boolean;`\n\nIf specified, the target query is invalidated on success. If you want to\ninvalidate all keys associated with an endpoint, have `mapKey` return null.\n\n### Advanced Usage\n\n`queryOptions` can be used for consistency if you need to prefetch queries or\nuse suspenses.\n\n```ts\nconst ctx = useServiceContext();\nconst { data: currentWorkspace } = useSuspenseQuery(\n  queryOptions(getUser, { userId }, ctx, {\n    staleTime: 60 * 1000,\n  }),\n);\n```\n\n`queryKey` generates a default query key for a service method and request. It is\nprovided as a convenience and can be overridden in the options param.\n\nIf you need to use the auto-generated query key manually, you can do so like\nthis:\n\n```ts\nawait queryClient.invalidateQueries({\n  queryKey: queryKey(listUsers, filter),\n});\n```\n\n## Contributing\n\nIf you find issues or spot possible improvements, please submit a pull-request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpup%2Freact-query-grpc-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpup%2Freact-query-grpc-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpup%2Freact-query-grpc-gateway/lists"}