Add Todos
Let's work on <AddTodo />
next. It will add a new Todo to the database. Therefore, it needs access to the
database. We are going to use the usePouch
hook for this.
// AddTodo.js
import React, { useState } from 'react'
import { usePouch } from 'use-pouchdb'
export default function AddTodo() {
const db = usePouch() // get the database
const [input, setInput] = useState('')
const handleAddTodo = async event => {
event.preventDefault()
const doc = {
_id: new Date().toJSON(), // give the document a unique id
type: 'todo',
text: input,
done: false,
}
await db.put(doc) // put the new document into the database
setInput('')
}
return (
<form onSubmit={handleAddTodo}>
<input
type="text"
value={input}
minLength="1"
onChange={event => {
setInput(event.target.value)
}}
/>
<button>Add Todo</button>
</form>
)
}
Let's go through this component:
First we get a reference to the database with usePouch()
. It is the database we provided to
<Provider />
in the last section.
The next instruction is the useState
hook, to store
what the user did enter.
We'll jump over the handleAddTodo
callback. And go to the JSX return:
We use a <form>
element with an onSubmit event listener to add the todo, whenever the user presses
enter/return/submit or clicks the <button>
. It will also only submit when the input has a length of
1 or more minlength='1'
(Isn't HTML awesome?).
When the user does submit, we handle the event in handleAddTodo
. The doc
object is our Todo-Document, which
we will add to the database. It's going be something like this:
{
"_id": "2020-05-25T21:42:17.275Z",
"type": "todo",
"text": "my first document!",
"done": false
}
Let's brake it down:
_id
The _id
is the unique identifier of a document. It must be unique to it's database. We can use the id later
to retrieve the document. Besides that, we can use it to sort documents and other tricks.
type
The type
field is technically not needed. It is a PouchDB and CouchDB convention to differentiate between
document types. Like type
in Redux Actions, but not needed.
You could also store the type in the _id
as a prefix: 'todo_2020-05-25T21:42:17.275Z'
. That is how the
Relational Pouch plugin
does it.
text
and done
They are our todo-data. The text and if it's done.
Next await db.put(doc)
. Here we put the document into the database (db). put()
returns a Promise. The Promise
only resolves once the document was successfully put into the database. If it's resolves the data is save.
put()
can fail! There are multiple reasons: The database could be destroyed, you don't have access to it,
or there is already a document with the same _id
. But, because we store the document on a local database and
with an _id
that is the current time with milliseconds, it is unlikely, but still possible.
setInput('')
resets the <input />
.
If put()
fails, the todo will not be added and the <input />
not reset. The user could then try again.
Normally you should always catch and handle a write/update error. PouchDB is a distributed system after all.
Displaying an error message or trying again (with a different id) would be enough for this use case.
Add AddTodo.js
to App.js
:
import React, { useState, useEffect } from 'react'
import './App.css'
import PouchDB from 'pouchdb-browser'
import { Provider } from 'use-pouchdb'
import AddTodo from './AddTodo'
...
return (
<Provider pouchdb={db}>
<div className="App">
<AddTodo />
</div>
</Provider>
)
That's it! We can now add Todos to the database! 🎉
Next up: list them!