For all SDK options targeting React, you always have 2 options:

  1. use simple hooks which are solely based on the API
  2. use the query hook that makes wraps the API in SWR

To use the simple hook that returns the Api, you can use:

import { useApi } from "bknd/client";

export default function App() {
   const api = useApi();
   // ...
}

useApiQuery([selector], [options])

This hook wraps the API class in an SWR hook for convenience. You can use any API endpoint supported, like so:

import { useApiQuery } from "bknd/client";

export default function App() {
   const { data, ...swr } = useApiQuery((api) => api.data.readMany("comments"));

   if (swr.error) return <div>Error</div>
   if (swr.isLoading) return <div>Loading...</div>

   return <pre>{JSON.stringify(data, null, 2)}</pre>
}

Props

  • selector: (api: Api) => FetchPromise

    The first parameter is a selector function that provides an Api instance and expects an endpoint function to be returned.

  • options: optional object that inherits from SWRConfiguration

    type Options<Data> = SWRConfiguration & {
       enabled?: boolean;
       refine?: (data: Data) => Data | any;
    }
    
    • enabled: Determines whether this hook should trigger a fetch of the data or not.
    • refine: Optional refinement that is called after a response from the API has been received. Useful to omit irrelevant data from the response (see example below).

Using mutations

To query and mutate data using this hook, you can leverage the parameters returned. In the following example we’ll also use a refine function as well as revalidateOnFocus (option from SWRConfiguration) so that our data keeps updating on window focus change.

import { useState } from "react";
import { useApiQuery } from "bknd/client";

export default function App() {
   const [text, setText] = useState("");
   const { data, api, mutate, ...q } = useApiQuery(
      (api) => api.data.readOne("comments", 1),
      {
         // filter to a subset of the response
         refine: (data) => data.data,
         revalidateOnFocus: true
      }
   );

   const comment = data ? data : null;

   useEffect(() => {
      setText(comment?.content ?? "");
   }, [comment]);

   if (q.error) return <div>Error</div>
   if (q.isLoading) return <div>Loading...</div>

   return (
      <form
         onSubmit={async (e) => {
            e.preventDefault();
            if (!comment) return;

            // this will automatically revalidate the query
            await mutate(async () => {
               const res = await api.data.updateOne("comments", comment.id, {
                  content: text
               });
               return res.data;
            });

            return false;
         }}
      >
         <input type="text" value={text} onChange={(e) => setText(e.target.value)} />
         <button type="submit">Update</button>
      </form>
   );
}

useEntity()

This hook wraps the endpoints of DataApi and returns CRUD options as parameters:

import { useState } from "react",
import { useEntity } from "bknd/client";

export default function App() {
   const [data, setData] = useState<any>();
   const { create, read, update, _delete } = useEntity("comments", 1);

   useEffect(() => {
      read().then(setData);
   }, []);

   return <pre>{JSON.stringify(data, null, 2)}</pre>
}

If you only supply the entity name as string without an ID, the read method will fetch a list of entities instead of a single entry.

Props

Following props are available when using useEntityQuery([entity], [id?]):

  • entity: string: Specify the table name of the entity
  • id?: number | string: If an id given, it will fetch a single entry, otherwise a list

Returned actions

The following actions are returned from this hook:

  • create: (input: object): Create a new entry
  • read: (query: Partial<RepoQuery> = {}): If an id was given, it returns a single item, otherwise a list
  • update: (input: object, id?: number | string): If an id was given, the id parameter is optional. Updates the given entry partially.
  • _delete: (id?: number | string): If an id was given, the id parameter is optional. Deletes the given entry.

useEntityQuery()

This hook wraps the actions from useEntity around SWR. The previous example would look like this:

import { useState } from "react",
import { useEntityQuery } from "bknd/client";

export default function App() {
   const { data } = useEntityQuery("comments", 1);

   return <pre>{JSON.stringify(data, null, 2)}</pre>
}

Using mutations

All actions returned from useEntityQuery are conveniently wrapped around the mutate function, so you don’t have think about this:

import { useState } from "react";
import { useEntityQuery } from "bknd/client";

export default function App() {
   const [text, setText] = useState("");
   const { data, update, ...q } = useEntityQuery("comments", 1);

   const comment = data ? data : null;

   useEffect(() => {
      setText(comment?.content ?? "");
   }, [comment]);

   if (q.error) return <div>Error</div>
   if (q.isLoading) return <div>Loading...</div>

   return (
      <form
         onSubmit={async (e) => {
            e.preventDefault();
            if (!comment) return;

            // this will automatically revalidate the query
            await update({ content: text });

            return false;
         }}
      >
         <input type="text" value={text} onChange={(e) => setText(e.target.value)} />
         <button type="submit">Update</button>
      </form>
   );
}