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 { useSignal, useComputed, Derive } from "kiru"

function App() {
  const name = useSignal("bob")
  const age = useSignal(42)
  const person = useComputed(() => ({ 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>
  )
}

Promise Support

<Derive /> also supports promises created by the usePromise hook. When deriving from a promise, you can use the fallback prop to show content while the promise is pending, 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 promises with <Derive />, or mix promises and signals:

import { useSignal, usePromise, Derive } from "kiru"

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

function Page() {
  const count = useSignal(0)
  const data = usePromise<ProductsResponse>(async (signal) => {
    const response = await fetch("https://dummyjson.com/products", { signal })
    if (!response.ok) throw new Error(response.statusText)
    return await response.json()
  }, [])

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

If any entry in the from prop is a promise, 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.

Related