> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bijection React

> React client library for interacting with your Bijection backend

Bijection React is the client library enabling your React application to interact
with your Bijection backend. It allows your frontend code to:

1. Call your [queries](/functions/query-functions),
   [mutations](/functions/mutation-functions) and
   [actions](/functions/actions)
2. Upload and display files from [File Storage](/file-storage/overview)
3. Authenticate users using [Authentication](/auth/overview)
4. Implement full text [Search](/search/overview) over your data

The Bijection React client is open source and available on
GitHub.

Follow the [React Quickstart](/quickstart/react) to get started with React
using [Vite](https://vitejs.dev/).

## Installation

Bijection React is part of the `bijection` SDK package, as `bijection/react`.
`bijection init --template react-vite` creates a React app with it installed.

The Bijection SDK (`bijection/react`, `bijection/browser`, …) is not published
to the npm registry. Your app declares it as a tarball from bijection.com, for
the version of your CLI (`bijection --version` prints it). Add this line to the
`dependencies` in your app's `package.json`:

```json package.json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
"bijection": "https://bijection.com/sdk/bijection-0.1.1.tgz"
```

Then install your app's dependencies with its package manager as usual (for
example `npm install`). The `react-vite` and `nextjs` templates of
`bijection init` write this line and run the install for you.

## Connecting to a backend

The [`BijectionReactClient`](/api/classes/react.BijectionReactClient) maintains a
connection to your Bijection backend, and is used by the React hooks described
below to call your functions.

First you need to create an instance of the client by giving it your backend
deployment URL. See
[Configuring Deployment URL](/client/react/project-setup) on how to pass in
the right value:

```jsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { BijectionProvider, BijectionReactClient } from "bijection/react";

const bijection = new BijectionReactClient("https://<your domain here>.bijection.cloud");
```

And then you make the client available to your app by passing it in to a
[`BijectionProvider`](/api/modules/react#bijectionprovider) wrapping your component
tree:

```jsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
reactDOMRoot.render(
  <React.StrictMode>
    <BijectionProvider client={bijection}>
      <App />
    </BijectionProvider>
  </React.StrictMode>,
);
```

## Fetching data

Your React app fetches data using the [`useQuery`](/api/modules/react#usequery)
React hook by calling your [queries](/functions/query-functions) via an
[`api`](/generated-api/api#api) object.

The `bijection dev` command generates this api object for you in the
`bijection/_generated/api.js` module to provide better autocompletion in JavaScript
and end-to-end type safety in
[TypeScript](/understanding/best-practices/typescript):

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useQuery } from "bijection/react";
import { api } from "../bijection/_generated/api";

export function App() {
  const data = useQuery(api.functions.myQuery);
  return data ?? "Loading...";
}
```

The `useQuery` hook returns `undefined` while the data is first loading and
afterwards the return value of your query.

### Query arguments

Arguments to your query follow the query name:

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export function App() {
  const a = "Hello world";
  const b = 4;
  const data = useQuery(api.functions.myQuery, { a, b });
  //...
}
```

### Reactivity

The `useQuery` hook makes your app automatically reactive: when the underlying
data changes in your database, your component rerenders with the new query
result.

The first time the hook is used it creates a subscription to your backend for a
given query and any arguments you pass in. When your component unmounts, the
subscription is canceled.

### Consistency

Bijection React ensures that your application always renders a consistent view of
the query results based on a single state of the underlying database.

Imagine a mutation changes some data in the database, and that 2 different
`useQuery` call sites rely on this data. Your app will never render in an
inconsistent state where only one of the `useQuery` call sites reflects the new
data.

### Experimental: query result object

If you want a richer result object to handle when querying, try
`useQuery_experimental`. It always returns an object with a `status` field, and
does not throw errors by default.

The `status` of the result object will be one of
`"pending" | "success" | "error"`. To help ensure correct handling of query
results, the return type requires that you check the `status` before accessing
other fields (`data` or `error`).

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useQuery_experimental as useQuery } from "bijection/react";
import { api } from "../bijection/_generated/api";

function TaskList() {
  const result = useQuery({
    query: api.tasks.list,
    args: { completed: false },
  });

  if (result.status === "pending") return <div>Loading...</div>;
  if (result.status === "error")
    return <div>Error: {result.error.message}</div>;
  // `status` guaranteed to be `"success"` at this point; `data` available.
  return result.data.map((task) => <div key={task._id}>{task.text}</div>);
}
```

If you're migrating existing code that leverages error boundaries, you can use
the `throwOnError: true` option to maintain that behavior.

### Paginating queries

See
[Paginating within React Components](/database/pagination#paginating-within-react-components).

### Skipping queries

<Accordion title="Advanced: Loading a query conditionally">
  With React it can be tricky to dynamically invoke a hook, because hooks cannot
  be placed inside conditionals or after early returns:

  ```tsx {1,7,9} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import { useQuery } from "bijection/react";
  import { api } from "../bijection/_generated/api";

  export function App() {
    // the URL `param` might be null
    const param = new URLSearchParams(window.location.search).get("param");
    // ERROR! React Hook "useQuery" is called conditionally. React Hooks must
    // be called in the exact same order in every component render.
    const data = param !== null ? useQuery(api.functions.read, { param }) : null;
    //...
  }
  ```

  For this reason `useQuery` can be "disabled" by passing in `"skip"` instead of
  its arguments:

  ```tsx {8} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import { useQuery } from "bijection/react";
  import { api } from "../bijection/_generated/api";

  export function App() {
    const param = new URLSearchParams(window.location.search).get("param");
    const data = useQuery(
      api.functions.read,
      param !== null ? { param } : "skip",
    );
    //...
  }
  ```

  When `"skip"` is used the `useQuery` doesn't talk to your backend at all and
  returns `undefined`.
</Accordion>

### One-off queries

<Accordion title="Advanced: Fetching a query from a callback">
  Sometimes you might want to read state from the database in response to a user
  action, for example to validate given input, without making any changes to the
  database. In this case you can use a one-off
  [`query`](/api/classes/react.BijectionReactClient#query) call, similarly to calling
  mutations and actions.

  The async method `query` is exposed on the `BijectionReactClient`, which you can
  reference in your components via the
  [`useBijection()`](/api/modules/react#usebijection) hook.

  ```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import { useBijection } from "bijection/react";
  import { api } from "../bijection/_generated/api";

  export function App() {
    const bijection = useBijection();
    return (
      <button
        onClick={async () => {
          console.log(await bijection.query(api.functions.myQuery));
        }}
      >
        Check
      </button>
    );
  }
  ```
</Accordion>

## Editing data

Your React app edits data using the
[`useMutation`](/api/modules/react#usemutation) React hook by calling your
[mutations](/functions/mutation-functions).

The `bijection dev` command generates this api object for you in the
`bijection/_generated/api.js` module to provide better autocompletion in JavaScript
and end-to-end type safety in
[TypeScript](/understanding/best-practices/typescript):

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useMutation } from "bijection/react";
import { api } from "../bijection/_generated/api";

export function App() {
  const doSomething = useMutation(api.functions.doSomething);
  return <button onClick={() => doSomething()}>Click me</button>;
}
```

The hook returns an `async` function which performs the call to the mutation.

### Mutation arguments

Arguments to your mutation are passed to the `async` function returned from
`useMutation`:

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export function App() {
  const a = "Hello world";
  const b = 4;
  const doSomething = useMutation(api.functions.doSomething);
  return <button onClick={() => doSomething({ a, b })}>Click me</button>;
}
```

### Mutation response and error handling

The mutation can optionally return a value or throw errors, which you can
[`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await):

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export function App() {
  const doSomething = useMutation(api.functions.doSomething);
  const onClick = () => {
    async function callBackend() {
      try {
        const result = await doSomething();
      } catch (error) {
        console.error(error);
      }
      console.log(result);
    }
    void callBackend();
  };
  return <button onClick={onClick}>Click me</button>;
}
```

Or handle as a
[`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise):

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export function App() {
  const doSomething = useMutation(api.functions.doSomething);
  const onClick = () => {
    doSomething()
      .catch((error) => {
        console.error(error);
      })
      .then((result) => {
        console.log(result);
      });
  };
  return <button onClick={onClick}>Click me</button>;
}
```

Learn more about [Error Handling](/functions/error-handling/error-handling)
in functions.

### Retries

Bijection React automatically retries mutations until they are confirmed to have
been written to the database. The Bijection backend ensures that despite multiple
retries, every mutation call only executes once.

Additionally, Bijection React will warn users if they try to close their browser
tab while there are outstanding mutations. This means that when you call a
Bijection mutation, you can be sure that the user's edits won't be lost.

### Optimistic updates

Bijection queries are fully reactive, so all query results will be automatically
updated after a mutation. Sometimes you may want to update the UI before the
mutation changes propagate back to the client. To accomplish this, you can
configure an *optimistic update* to execute as part of your mutation.

Optimistic updates are temporary, local changes to your query results which are
used to make your app more responsive.

See [Optimistic Updates](/client/react/optimistic-updates) on how to
configure them.

## Calling third-party APIs

Your React app can read data, call third-party services, and write data with a
single backend call using the [`useAction`](/api/modules/react#useaction) React
hook by calling your [actions](/functions/actions).

Like `useQuery` and `useMutation`, this hook is used with the `api` object
generated for you in the `bijection/_generated/api.js` module to provide better
autocompletion in JavaScript and end-to-end type safety in
[TypeScript](/understanding/best-practices/typescript):

```tsx src/App.tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useAction } from "bijection/react";
import { api } from "../bijection/_generated/api";

export function App() {
  const doSomeAction = useAction(api.functions.doSomeAction);
  return <button onClick={() => doSomeAction()}>Click me</button>;
}
```

The hook returns an `async` function which performs the call to the action.

### Action arguments

Action arguments work exactly the same as
[mutation arguments](#mutation-arguments).

### Action response and error handling

Action response and error handling work exactly the same as
[mutation response and error handling](#mutation-response-and-error-handling).

Actions do not support automatic retries or optimistic updates.

## Under the hood

The [`BijectionReactClient`](/api/classes/react.BijectionReactClient) connects to your
Bijection deployment by creating a
[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). The
WebSocket provides a 2-way communication channel over TCP. This allows Bijection to
push new query results reactively to the client without the client needing to
poll for updates.

If the internet connection drops, the client will handle reconnecting and
re-establishing the Bijection session automatically.
