Notr Logo

Components

Client and server building blocks when using Drizzleasy.

Client Hook: useOptimisticCrud

'use client'

import { useOptimisticCrud, createFn } from '@remcostoeten/drizzleasy'

type TTodo = { id: string; title: string; completed: boolean }

type TProps = { initialTodos: TTodo[] }

export function TodoList(props: TProps) {
  const { data, isPending, optimisticCreate } = useOptimisticCrud<TTodo>(props.initialTodos)
  const create = createFn<TTodo>()

  function handleCreate(formData: FormData) {
    const title = String(formData.get('title') || '')
    optimisticCreate({ title, completed: false }, function onCreate() {
      return create('todos')({ id: crypto.randomUUID(), title, completed: false })
    })
  }

  return (
    <form action={handleCreate}>
      <input name="title" placeholder="Add todo" />
      <button disabled={isPending}>{isPending ? 'Adding…' : 'Add'}</button>
    </form>
  )
}

Transitions: withTransition

'use client'

import { withTransition } from '@remcostoeten/drizzleasy'

async function saveUserAction() {
  'use server'
  // ... perform mutation and return { data?, error? }
}

const save = withTransition(saveUserAction)

export function SaveButton() {
  return <button onClick={save}>Save</button>
}

Server actions pattern

'use server'

import { createFn, readFn, updateFn, destroyFn } from '@remcostoeten/drizzleasy'

type TUser = { id: string; email: string; name: string; status: 'active' | 'inactive' }

const create = createFn<TUser>()
const read = readFn<TUser>()
const update = updateFn<TUser>()
const destroy = destroyFn<TUser>()

export async function createUser(data: { email: string; name: string }) {
  return create('users')({ id: crypto.randomUUID(), email: data.email, name: data.name, status: 'active' })
}

export async function getUsers() {
  return read('users')()
}

export async function deactivateUser(id: string) {
  return update('users')(id, { status: 'inactive' })
}

export async function removeUser(id: string) {
  return destroy('users')(id)
}