Optimistic Todo List
Create, toggle, and remove todos immediately with automatic rollback.
Result
Todo interactions update the list before the mutation response. Convex confirmation replaces the optimistic view; failures restore the previous result.
Create
const createTodo = useConvexMutation(api.todos.create, {
optimisticUpdate: (store, args) => {
updateQuery({
query: api.todos.list,
args: {},
store,
updater: (todos) => [
{
_id: crypto.randomUUID() as Id<'todos'>,
_creationTime: Date.now(),
text: args.text,
completed: false,
},
...(todos ?? []),
],
})
},
})Toggle
const toggleTodo = useConvexMutation(api.todos.toggle, {
optimisticUpdate: (store, args) => {
updateQuery({
query: api.todos.list,
args: {},
store,
updater: (todos) =>
(todos ?? []).map((todo) =>
todo._id === args.todoId ? { ...todo, completed: !todo.completed } : todo,
),
})
},
})Remove
const removeTodo = useConvexMutation(api.todos.remove, {
optimisticUpdate: (store, args) => {
deleteFromQuery({
query: api.todos.list,
args: {},
store,
shouldDelete: (todo) => todo._id === args.todoId,
})
},
})Security boundary
The backend loads the todo and checks ownership before toggling or deleting. The optimistic predicate is presentation only.
Verify rollback
Temporarily make each mutation reject after validation and confirm:
- a created temporary todo disappears;
- a toggle returns to its server value;
- a removed todo reappears;
- the error is visible and the form remains usable.
Remove the forced failures after verification.