Writing data to Firestore

Learn how to write, update and delete data using Firestore in Makerkit

Similarly to reading data from Firestore, we may want to create a `custom hook`` also when we write, update or delete data.

Assuming we have an entity called tasks, and we want to create a hook to create a new Task, we can do the following.

  1. First, we create a new hook at lib/tasks/hooks/use-create-task.ts
  2. We add the tasks collection name to lib/firestore-collections
  3. Wrap the addDoc function from Firestore within a useCallback hook
import { TASKS_COLLECTION } from '~/lib/firestore-collections'; function useCreateTask() { const firestore = useFirestore(); const tasksCollection = collection(firestore, TASKS_COLLECTION); return useCallback( (task: Task) => { return addDoc(tasksCollection, task); }, [tasksCollection] ); }

And now, we could use this hook within a component:

function Component() { const createTask = useCreateTask(); return <MyForm onSubmit={task => createTask(task)} /> }

Let's take a look at a complete example of a form that makes a request using the hook above:

const CreateTaskForm = () => { const createTask = useCreateTask(); const { setLoading, state } = useRequestState(); const router = useRouter(); const organization = useCurrentOrganization(); const organizationId = organization?.id as string; const onCreateTask: FormEventHandler<HTMLFormElement> = useCallback( async (event) => { event.preventDefault(); const target = event.currentTarget; const data = new FormData(target); const name = data.get('name') as string; const dueDate = data.get('dueDate') as string; setLoading(true); const task = { organizationId, name, dueDate, description: ``, done: false, }; const promise = createTask(task).then(() => { return router.push(`/tasks`); }); await toaster.promise(promise, { success: `Task created!`, error: `Ops, error!`, loading: `Creating task...`, }); }, [router, createTask, organizationId, setLoading] ); return ( <div> <form onSubmit={onCreateTask}> <div className={'flex flex-col space-y-3'}> <TextField.Label> Name <TextField.Input required name={'name'} placeholder={'ex. Launch on IndieHackers'} /> <TextField.Hint>Hint: whatever you do, ship!</TextField.Hint> </TextField.Label> <TextField.Label> Due date <TextField.Input required defaultValue={getDefaultDueDate()} name={'dueDate'} type={'date'} /> </TextField.Label> <div className={ 'flex flex-col space-y-2 md:space-y-0 md:space-x-2' + ' md:flex-row' } > <Button loading={state.loading}> <If condition={state.loading} fallback={<>Create Task</>}> Creating Task... </If> </Button> <Button color={'transparent'} href={'/tasks'}> Go back </Button> </div> </div> </form> </div> ); }; function getDefaultDueDate() { const date = new Date(); const year = date.getFullYear(); const month = pad(date.getMonth() + 1); const day = pad(date.getDate() + 1); return `${year}-${month}-${day}`; } function pad(n: number) { return n < 10 ? `0${n}` : n.toString(); } export default CreateTaskForm;

Subscribe to our Newsletter
Get the latest updates about React, Remix, Next.js, Firebase, Supabase and Tailwind CSS