# React Setup (https://v2.s3.dimah.dev/docs/react/setup)

## Install [#install]

```npm
npm i @dimah-s3/react@beta @dimah-s3/core@beta @fuma-translate/react
```

`@dimah-s3/react` needs React 19.2. `@dimah-s3/core` holds `APIError` and the
protocol helpers, and `@fuma-translate/react` powers the translated strings.

## 1. Create the client [#1-create-the-client]

<Tabs items={["@dimah-s3/server", "Bring your own backend"]}>

<Tab value="@dimah-s3/server">

`createS3Client` returns the API object plus a bound `Provider` and a typed
`useApi`.

```ts title="lib/s3-client.ts"
"use client";

import { createS3Client } from "@dimah-s3/react";

export const s3Client = createS3Client();
export const S3Provider = s3Client.Provider;
```

To change the base path, send cookies, or add headers:

```ts
export const s3Client = createS3Client({
  basePath: "/api/s3", // [!code ++]
  credentials: "include", // [!code ++]
  headers: async () => ({
    // [!code ++]
    Authorization: `Bearer ${await getAuthToken()}`, // [!code ++]
  }), // [!code ++]
});
```

</Tab>

<Tab value="Bring your own backend">

Implement `S3Api` with `defineApi` from the engine entry, then pass it to
`S3Provider`:

```tsx title="components/s3-provider.tsx"
"use client";

import { S3Provider } from "@dimah-s3/react";
import { api } from "@/lib/s3-api";

export function AppS3Provider({ children }: { children: React.ReactNode }) {
  return <S3Provider api={api}>{children}</S3Provider>;
}
```

See [Bring Your Own Backend](https://v2.s3.dimah.dev/docs/react/custom-backend) for the contract.

</Tab>

</Tabs>

## 2. Mount S3Provider [#2-mount-s3provider]

Mount the provider near your app root:

<Tabs items={["Next.js (App Router)", "Vite / SPA"]}>

<Tab value="Next.js (App Router)">

```tsx title="app/layout.tsx"
import { S3Provider } from "@/lib/s3-client"; // [!code ++]

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {/* [!code ++] */}
        <S3Provider>{children}</S3Provider>
      </body>
    </html>
  );
}
```

</Tab>

<Tab value="Vite / SPA">

```tsx title="src/main.tsx"
import React from "react";
import ReactDOM from "react-dom/client";
import { S3Provider } from "./lib/s3-client"; // [!code ++]
import { App } from "./app";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    {/* [!code ++] */}
    <S3Provider>
      <App />
    </S3Provider>
  </React.StrictMode>,
);
```

</Tab>

</Tabs>

The provider also takes `translations` and `locale`. See
[Internationalization](https://v2.s3.dimah.dev/docs/i18n).

## 3. Call your first hook [#3-call-your-first-hook]

Use `useUpload` with a route name from your server config:

```tsx title="app/file-uploader.tsx"
"use client";

import { useUpload } from "@dimah-s3/react";

export function FileUploader() {
  const upload = useUpload({ route: "avatar" });

  return (
    <div
      {...upload.getRootProps({
        className: "cursor-pointer rounded border p-4 text-center",
      })}
    >
      <input {...upload.getInputProps()} />
      {upload.isPending
        ? `Uploading: ${upload.progress.percent}%`
        : "Click or drop a file here"}
    </div>
  );
}
```

Every hook takes an optional `api` to use instead of the provider's.

---

## Shared and server modules [#shared-and-server-modules]

The root entry is a client module. Plain functions that do not need React,
such as `defineApi`, `memoryObjectSource`, and `createLocalStorageStore`,
ship from `@dimah-s3/react/engine`, which has no `"use client"` directive:

```ts title="lib/s3-api.ts"
import { defineApi } from "@dimah-s3/react/engine";
```

See [Engine](https://v2.s3.dimah.dev/docs/react/guides/engine) for the full list.

---

## TypeScript route inference [#typescript-route-inference]

Type route names across hooks and components:

```ts title="lib/s3-routes.ts"
import type { InferS3Routes } from "@dimah-s3/core";
import type { s3 } from "@/lib/s3";

declare module "@dimah-s3/core" {
  // [!code ++]
  interface DimahS3Routes extends Record<InferS3Routes<typeof s3>, true> {} // [!code ++]
}
```

---

## Type reference [#type-reference]

```ts
import type { CreateS3ClientOptions } from "@dimah-s3/core";
```

### CreateS3ClientOptions [#creates3clientoptions]

<AutoTypeTable
  path="packages/core/src/create-s3-client.ts"
  name="CreateS3ClientOptions"
/>

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="Where do file constraints come from?">

From the server. `useUpload` loads the route catalog (`GET /routes`) before it
presigns and checks each file against the route's `fileTypes` and
`maxFileSize`. `accept` and `maxFileSize` on the hook can only narrow them.

</Accordion>

<Accordion title="How do I pass auth tokens or cookies to the API?">

Pass `headers` (a value or an async function) or `credentials: "include"` to
`createS3Client`:

```ts
export const s3Client = createS3Client({
  credentials: "include", // [!code ++]
  headers: async () => ({
    // [!code ++]
    Authorization: `Bearer ${getStoredToken()}`, // [!code ++]
  }), // [!code ++]
});
```

</Accordion>

</Accordions>
