diff --git a/packages/react/spec/GadgetProvider.spec.tsx b/packages/react/spec/GadgetProvider.spec.tsx
index f8384461d..ab88658e8 100644
--- a/packages/react/spec/GadgetProvider.spec.tsx
+++ b/packages/react/spec/GadgetProvider.spec.tsx
@@ -4,7 +4,7 @@ import { GadgetConnection } from "@gadgetinc/api-client-core";
import { renderHook } from "@testing-library/react";
import type { ReactNode } from "react";
import React from "react";
-import { Provider, useConnection } from "../src/GadgetProvider";
+import { Provider, useApi, useConnection } from "../src/GadgetProvider";
import { mockUrqlClient } from "./testWrapper";
describe("GadgetProvider", () => {
@@ -37,6 +37,16 @@ describe("GadgetProvider", () => {
expect(result).toBeTruthy();
});
+ test("internal components can access the api client when wrapped in the provider which is passed an api client", () => {
+ const { result } = renderHook(() => useApi(), {
+ wrapper: (props: { children: ReactNode }) => {
+ return {props.children};
+ },
+ });
+
+ expect(result.current).toBe(mockApiClient);
+ });
+
test("the provider errors when not passed anything", () => {
expect(() =>
renderHook(() => useConnection(), {
@@ -62,4 +72,18 @@ describe("GadgetProvider", () => {
`"Invalid Gadget API client passed to component -- please pass an instance of your generated client, like !"`
);
});
+
+ test("internal components can't access the api client when wrapped in the provider which is passed an urql client", () => {
+ expect(() =>
+ renderHook(() => useApi(), {
+ wrapper: (props: { children: ReactNode }) => {
+ return {props.children};
+ },
+ })
+ ).toThrowErrorMatchingInlineSnapshot(`
+ "useApi hook called in context with deprecated convention. Please ensure you are wrapping this hook with the component from @gadgetinc/react and passing it an instance of your api client, like .
+
+ The component is currently being passed a value, like . Please update this to ."
+ `);
+ });
});
diff --git a/packages/react/src/GadgetProvider.tsx b/packages/react/src/GadgetProvider.tsx
index 385656b19..644b149e3 100644
--- a/packages/react/src/GadgetProvider.tsx
+++ b/packages/react/src/GadgetProvider.tsx
@@ -1,7 +1,6 @@
import type { AnyClient, GadgetConnection } from "@gadgetinc/api-client-core";
import { $gadgetConnection, isGadgetClient } from "@gadgetinc/api-client-core";
-import type { ReactNode } from "react";
-import React from "react";
+import React, { ReactNode, useContext } from "react";
import type { Client as UrqlClient } from "urql";
import { Provider as UrqlProvider } from "urql";
@@ -89,8 +88,12 @@ export function Provider(props: ProviderProps | DeprecatedProviderProps) {
);
}
+/**
+ * Get the current `GadgetConnection` object from React context.
+ * Must be called within a component wrapped by the `` component.
+ **/
export const useConnection = () => {
- const urqlClient = React.useContext(GadgetUrqlClientContext);
+ const urqlClient = useContext(GadgetUrqlClientContext);
if (!urqlClient) {
throw new Error("No urql client object in React context, have you added the wrapper component from @gadgetinc/react?");
}
@@ -108,3 +111,31 @@ export const useConnection = () => {
return connection;
};
+
+/**
+ * Get the current `api` object from React context
+ * Must be called within a component wrapped by the `` component.
+ **/
+export const useApi = () => {
+ const api = useContext(GadgetClientContext);
+ const urqlClient = useContext(GadgetUrqlClientContext);
+ if (!api) {
+ if (urqlClient) {
+ throw new Error(
+ `useApi hook called in context with deprecated convention. Please ensure you are wrapping this hook with the component from @gadgetinc/react and passing it an instance of your api client, like .
+
+ The component is currently being passed a value, like . Please update this to .`
+ );
+ } else {
+ throw new Error(
+ `useApi hook called in context where no Gadget API client is available. Please ensure you are wrapping this hook with the component from @gadgetinc/react.
+
+ Possible remedies:
+ - ensuring you have the component wrapped around your hook invocation
+ - ensuring you are passing an api client instance to the provider, usually
+ - ensuring your @gadget-client/ package and your @gadgetinc/react package are up to date`
+ );
+ }
+ }
+ return api;
+};