Derive

Similar to <For>, Derive allows you to easily create fine-grained reactivity in JSX. The <Derive> component produces a JSX element that automatically updates whenever the provided from signal changes.

import { signal, computed, Derive } from "kiru"

function App() {
  const name = signal("bob")
  const age = signal(42)
  const person = computed(() => ({ name: name.value, age: age.value }))

  return () => (
    <div>
      <input bind:value={name} />
      <input type="number" bind:value={age} />
      <Derive from={person}>
        {(person) => (
          <div>
            {person.name} is {person.age} years old
          </div>
        )}
      </Derive>
      {/* You can also use an object as the `from` prop to derive from multiple signals */}
      <Derive from={{ name, age }}>
        {({ name, age }) => (
          <div>
            {name} is {age} years old
          </div>
        )}
      </Derive>
    </div>
  )
}

Async Rendering

<Derive /> also supports resources. When deriving from a Resource, you can use the fallback prop to show content while the data is loading, and the render function receives an isStale parameter that indicates whether the data is stale (i.e., a new request is in progress).

You can use multiple resources with <Derive />, or mix resources and signals:

import { signal, resource, Derive } from "kiru"

type ProductsResponse = {
  products: Array<{
    id: number
    title: string
  }>
}

function Page() {
  const search = signal("")
  const data = resource(search, async (search, { signal }) => {
    const response = await fetch(
      `https://dummyjson.com/products/search?q=${search}`,
      { signal }
    )
    if (!response.ok) throw new Error(response.statusText)
    return response.json() as Promise<ProductsResponse>
  })

  return () => (
    <>
      <input bind:value={search} />
      <Derive from={data} fallback={<div>Loading...</div>}>
        {(data, isStale) => (
          <div className={isStale ? "opacity-50" : ""}>
            <ul>
              {data.products.map((product) => (
                <li key={product.id}>{product.title}</li>
              ))}
            </ul>
          </div>
        )}
      </Derive>
    </>
  )
}

If any entry in the from prop is a resource, you can use the fallback prop. By default, <Derive /> uses SWR-style behavior where stale data is shown while new data loads. If you never want to show stale content, you can use the mode prop (accepted values: "swr" | "fallback"), which defaults to "swr". Setting it to "fallback" will render the fallback whenever the data is stale.