Skip to content

Update README.md #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 15, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 64 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,77 +92,78 @@ npx convex env set R2_BUCKET xxxxx

File uploads to R2 typically use signed urls. The R2 component provides a React
hook that handles the entire upload processs:

- generates the signed url
- uploads the file to R2
- stores the file's metadata in your Convex database

1. Instantiate a R2 component client in a file in your app's `convex/` folder:
```ts
// convex/example.ts
import { R2 } from "@convex-dev/r2";
import { components } from "./_generated/api";

export const r2 = new R2(components.r2);

export const { generateUploadUrl, syncMetadata } = r2.clientApi({
checkUpload: async (ctx, bucket) => {
// const user = await userFromAuth(ctx);
// ...validate that the user can upload to this bucket
},
onUpload: async (ctx, key) => {
// ...do something with the key
// Runs in the `syncMetadata` mutation, as the upload is performed from the
// client side. Convenient way to create relations between the newly created
// object key and other data in your Convex database. Runs after the `checkUpload`
// callback.
},
});
```
```ts
// convex/example.ts
import { R2 } from "@convex-dev/r2";
import { components } from "./_generated/api";

export const r2 = new R2(components.r2);

export const { generateUploadUrl, syncMetadata } = r2.clientApi({
checkUpload: async (ctx, bucket) => {
// const user = await userFromAuth(ctx);
// ...validate that the user can upload to this bucket
},
onUpload: async (ctx, key) => {
// ...do something with the key
// Runs in the `syncMetadata` mutation, as the upload is performed from the
// client side. Convenient way to create relations between the newly created
// object key and other data in your Convex database. Runs after the `checkUpload`
// callback.
},
});
```

2. Use the `useUploadFile` hook in a React component to upload files:

```tsx
// src/App.tsx
import { FormEvent, useRef, useState } from "react";
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";
import { useUploadFile } from "@convex-dev/r2/react";

export default function App() {

// Passing the entire api exported from `convex/example.ts` to the hook.
// This must include `generateUploadUrl` and `syncMetadata` from the r2 client api.
const uploadFile = useUploadFile(api.example);
const imageInput = useRef<HTMLInputElement>(null);
const [selectedImage, setSelectedImage] = useState<File | null>(null);

async function handleUpload(event: FormEvent) {
event.preventDefault();

// The file is uploaded to R2, metadata is synced to the database, and the
// key of the newly created object is returned.
await uploadFile(selectedImage!);
setSelectedImage(null);
imageInput.current!.value = "";
}
return (
<form onSubmit={handleUpload}>
<input
type="file"
accept="image/*"
ref={imageInput}
onChange={(event) => setSelectedImage(event.target.files![0])}
disabled={selectedImage !== null}
/>
<input
type="submit"
value="Upload"
disabled={selectedImage === null}
/>
</form>
);
}
```
```tsx
// src/App.tsx
import { FormEvent, useRef, useState } from "react";
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";
import { useUploadFile } from "@convex-dev/r2/react";

export default function App() {
// Passing the entire api exported from `convex/example.ts` to the hook.
// This must include `generateUploadUrl` and `syncMetadata` from the r2 client api.
const uploadFile = useUploadFile(api.example);
const imageInput = useRef<HTMLInputElement>(null);
const [selectedImage, setSelectedImage] = useState<File | null>(null);

async function handleUpload(event: FormEvent) {
event.preventDefault();

// The file is uploaded to R2, metadata is synced to the database, and the
// key of the newly created object is returned.
await uploadFile(selectedImage!);
setSelectedImage(null);
imageInput.current!.value = "";
}
return (
<form onSubmit={handleUpload}>
<input
type="file"
accept="image/*"
ref={imageInput}
onChange={event => setSelectedImage(event.target.files![0])}
disabled={selectedImage !== null}
/>
<input
type="submit"
value="Upload"
disabled={selectedImage === null}
/>
</form>
);
}
```

### Using a custom object key

Expand Down Expand Up @@ -326,4 +327,4 @@ export const page = query({
});
```

<!-- END: Include on https://convex.dev/components -->
<!-- END: Include on https://convex.dev/components -->