Skip to content
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
63 changes: 59 additions & 4 deletions docs/pages/api-reference/liveblocks-react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3776,14 +3776,43 @@ Returns a function that uploads a file to the current room. The function
resolves to a [`LiveFile`](/docs/api-reference/liveblocks-client#LiveFile) that
can be stored in Storage.

Because [`useMutation`](/docs/api-reference/liveblocks-react#useMutation)
[doesn’t support async callbacks](/docs/api-reference/liveblocks-react#useMutation-async),
await the upload outside of the mutation, then pass the resulting `LiveFile`
into it.

```tsx
import { useCallback } from "react";
import { useMutation, useUploadFile } from "@liveblocks/react/suspense";
import type { LiveFile } from "@liveblocks/client";

const uploadFile = useUploadFile();
function UploadFile() {
const uploadFile = useUploadFile();

const setFile = useMutation(async ({ storage }, file: File) => {
storage.set("file", await uploadFile(file));
}, []);
const setFile = useMutation(({ storage }, file: LiveFile) => {
storage.set("file", file);
}, []);

const handleFile = useCallback(
async (file: File) => {
const liveFile = await uploadFile(file);
setFile(liveFile);
},
[uploadFile, setFile]
);

return (
<input
type="file"
onChange={(e) => {
const file = e.currentTarget.files?.[0];
if (file) {
handleFile(file);
}
}}
/>
);
}
```

The function accepts the same arguments and returns the same result as
Expand Down Expand Up @@ -4092,6 +4121,32 @@ return <button onClick={deleteSelectedShapes} />;
Mutations are automatically batched, so when using `useMutation` there’s no need
to use `useBatch`, or call `room.batch()` manually.

#### Doesn’t work with async functions [#useMutation-async]

Because mutations are batched with
[`room.batch`](/docs/api-reference/liveblocks-client#Room.batch), which
[cannot take an `async` function](/docs/api-reference/liveblocks-client#Doesn't-work-with-async-functions),
the mutation function passed to `useMutation` cannot be `async` either.

```tsx
// ❌ Won’t work
const updateFill = useMutation(async ({ storage }) => {
const fill = await fetchColor();
storage.get("shapes").get("circle1").set("fill", fill);
}, []);

// ✅ Will work
const updateFill = useMutation(({ storage }, fill: string) => {
storage.get("shapes").get("circle1").set("fill", fill);
}, []);

// …with the async work happening outside of the mutation
const handleClick = useCallback(async () => {
const fill = await fetchColor();
updateFill(fill);
}, [updateFill]);
```

#### ESLint rule [#useMutation-lint-rule] [@keywords=["exhaustive-deps", "additionalHooks", "eslint-plugin-react-hooks"]]

If you are using ESLint in your project, and are using
Expand Down
Loading