Data Mutation
This page information on how you can mutate data on Firestore, such as updating and deleting, or running transactions and write batches.
All hooks are built upon the useMutation
hook, making it super simple to handle loading states, success and errors.
Adding a document to a collection
To add a document to a collection, use the useFirestoreCollectionMutation
hook.
It accepts a CollectionReference
and when the mutation is triggered, the provided
data is added as a new document.
import { useFirestoreCollectionMutation } from "@react-query-firebase/firestore";
import { collection } from "firebase/firestore";
import { firestore } from "./firebase";
function AddDocument() {
const ref = collection(firestore, "products");
const mutation = useFirestoreCollectionMutation(ref);
return (
<>
<button
disabled={mutation.isLoading}
onClick={() => {
mutation.mutate({
name: "New product!",
price: 10,
});
}}
>
Add document
</button>
{mutation.isError && <p>{mutation.error.message}</p>}
</>
);
}
Setting / Updating a document
If you need to set or update the data on an existing document, use
the useFirestoreDocumentMutation
hook.
import { collection, doc } from "firebase/firestore";
import { useFirestoreDocumentMutation } from "@react-query-firebase/firestore";
import { firestore } from "./firebase";
function SetDocument() {
const collection = collection(firestore, "products");
const ref = doc(collection, "123");
const mutation = useFirestoreDocumentMutation(ref);
return (
<>
<button
disabled={mutation.isLoading}
onClick={() => {
mutation.mutate({
name: "New product!",
price: 20,
});
}}
>
Set document
</button>
{mutation.isError && <p>{mutation.error.message}</p>}
</>
);
}
In this example, the document will be overwritten with the provided data.
You can optionally pass SetOptions
to indiciate you wish to merge data instead:
const mutation = useFirestoreDocumentMutation(ref, {
merge: true,
});
Deleting a document
To delete a document from your collection, use the useFirestoreDocumentDeletion
hook.
import { collection, doc } from "firebase/firestore";
import { useFirestoreDocumentDeletion } from "@react-query-firebase/firestore";
import { firestore } from "./firebase";
function DeleteDocument() {
const collection = collection(firestore, "products");
const ref = doc(collection, "456");
const mutation = useFirestoreDocumentDeletion(ref);
return (
<>
<button
disabled={mutation.isLoading}
onClick={() => {
mutation.mutate();
}}
>
Delete document
</button>
{mutation.isError && <p>{mutation.error.message}</p>}
</>
);
}
Running Transactions
To run a transaction, use the useFirestoreTransaction
hook. The hook
allows you to define the transaction function and execute it when ready.
import { collection, doc } from "firebase/firestore";
import { useFirestoreTransaction } from "@react-query-firebase/firestore";
import { firestore } from "./firebase";
function LikeButton() {
const collection = collection(firestore, "products");
const ref = doc(collection, "123");
const mutation = useFirestoreTransaction(ref, async (tsx) => {
// Get the document
const doc = await tsx.get(ref);
const newLikes = doc.data().likes + 1;
// Increase the `likes` count
tsx.update(ref, {
likes: newLikes,
});
return newLikes;
});
return (
<>
<button
disabled={mutation.isLoading}
onClick={() => {
mutation.mutate();
}}
>
Like!
</button>
{mutation.isError && <p>{mutation.error.message}</p>}
</>
);
}
To learn more about transactions, read the Firestore guide.
Write Batches
To execute many updates at once, use the useFirestoreWriteBatch
hook.
Provide the hook with a WriteBatch
instance, add batches writes and commit
the batch with the mutation trigger.
import { writeBatch, collection, doc } from "firebase/firestore";
import { useFirestoreWriteBatch } from "@react-query-firebase/firestore";
import { firestore } from "./firebase";
function WriteBatchDocuments() {
// Define the WriteBatch instance
const batch = writeBatch(firestore);
const ref = doc(collection(firestore, "products"), "123");
const mutation = useFirestoreWriteBatch(batch);
return (
<>
{/* Update the WriteBatch instance */}
<button onClick={() => batch.delete(ref)}>Stage Deletion</button>
{/* Commit the write batch */}
<button
disabled={mutation.isLoading}
onClick={() => {
mutation.mutate();
}}
>
Like!
</button>
{mutation.isError && <p>{mutation.error.message}</p>}
</>
);
}
Side Effects
All mutation hooks are built on-top of the useMutation
hook,
and allow you define mutation side effects:
const mutation = useFirestoreCollectionMutation(ref, {
onSuccess() {
toast.success("Document added!");
},
onError(error) {
toast.error("Failed to add document!");
},
onMutate() {
toast.info("Adding document...");
},
});
// or on the mutation function!
mutation.mutate(
{ name: "New Product!" },
{
onSuccess() {
toast.success("Document added!");
},
onError(error) {
toast.error("Failed to add document!");
},
onMutate() {
toast.info("Adding document...");
},
}
);