Skip to main content

My First Replicache Feature

Let's see how easy it is to add a full-stack feature using Replicache. We will add an "urgent" flag to our Todos, and the ability to toggle and persist this property.

Modify the Model

First let's add the urgent boolean to the Todo model. The example app uses zod to describe the shape of the domain objects.

import {z} from 'zod';
import {entitySchema, generate, Update} from '@rocicorp/rails';

export const todoSchema = entitySchema.extend({
text: z.string(),
completed: z.boolean(),
sort: z.number(),

// add this property
urgent: z.optional(z.boolean()),

Add a Mutator

We need to ensure that we have a mutator that can handle the new logic.

The example app already has create, update, and delete mutators generated by the @rocicorp/rails helper library. The updateTodo mutator already handles any fields, so there's nothing to do here 🎉.

This pattern of reusing CRUD mutators for simple actions is common in Replicache apps — specific mutators are written to handle more specialized logic.

export const [createTodo, getTodo, updateTodo, deleteTodo, listTodos] =
generate('todo', todoSchema);
import {createTodo, updateTodo, deleteTodo} from './todo';

export const mutators = {

Add a Toggle Button

We need to add a UI element so that the user can toggle the "urgent" flag. This is simple to do since the mutator we need is already available in this component as onUpdate.

<div className="view">
{/* add this button to the view div */}
style={{all: 'revert'}}
onClick={() => onUpdate({id, urgent: !todo.urgent})}
<button className="destroy" onClick={() => onDelete()} />

At this point, we have actually finished the basic plumbing of our feature. Clicking on this button will: 1) change the state of our app (immediately), 2) persist that change, and 3) cause that change to be synchronized in real time to other browsers.

Show the "urgent" flag in the UI

Just to prove to ourselves that this is happening, let's render some text when the urgent flag is set:

<label onDoubleClick={handleDoubleClick}>
{/* Add the URGENT label if urgent flag is set */}
{todo.text} {todo.urgent && '(URGENT!)'}

It's not beautiful, but you get the idea. In summary, developers can often implement a feature by writing relatively simple code in one place. The data changes associated with that feature will automatically be full-stack and synchronized to other instances of the app.