---
title: "SDK (React)"
description: "Use the bknd SDK for React"
icon: React
tags: ["documentation"]
---

There are 4 useful hooks to work with your backend:

1. simple hooks which are solely based on the [API](/usage/sdk):
   - [`useApi`](#useapi)
   - [`useEntity`](#useentity)
2. query hooks that wraps the API in [SWR](https://swr.vercel.app/):
   - [`useApiQuery`](#useapiquery)
   - [`useEntityQuery`](#useentityquery)

## Setup

In order to use them, make sure you wrap your `<App />` inside `<ClientProvider />`, so that these hooks point to your bknd instance:

```tsx
import { ClientProvider } from "bknd/client";

export default function App() {
  return <ClientProvider>{/* your app */}</ClientProvider>;
}
```

For all other examples below, we'll assume that your app is wrapped inside the `ClientProvider`.

## `useApi()`

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

```tsx
import { useApi } from "bknd/client";

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

## `useApiQuery()`

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

```tsx
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`

```ts
type Options<Data> = import("swr").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.

```tsx
import { useEffect, 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:

```tsx
import { useState, useEffect } 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:

```tsx
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:

```tsx
import { useState, useEffect } 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>
  );
}
```
