ref

Create writable state and recursively convert nested object and array fields to refs.

refReactivity

Create writable state and recursively convert nested object and array fields to refs.

Overview

The ref function converts a given value and its nested properties into ref objects recursively, returning a ref object that reflects the structure of the input value.

Try It Online

Try it live

Compare deep, copied, and shallow stateLive API
REF / DEEPAda

Nested properties are refs.

CREF / COPY FIRSTAda

Original still says Ada.

SREF / SHALLOWAda

Replace the plain object to notify.

isRef(deep) / isDeepRef(deep)
true / true
isDeepRef(shallow) / unref(name)
false / Ada
{
  "profile": {
    "name": "Ada"
  }
}
import {
  computed,
  cref,
  flatten,
  html,
  isDeepRef,
  isRef,
  ref,
  sref,
  unref,
} from 'regor'

export function createState(interactive = false) {
  const original = { profile: { name: 'Ada' } }
  const deep = ref({ profile: { name: 'Ada' } })
  const copied = cref(original)
  const shallow = sref({ profile: { name: 'Ada' } })
  const name = ref('Grace')
  const apply = () => {
    deep().profile().name(name())
    copied().profile().name(name())
    shallow({ profile: { name: name() } })
  }
  return {
    interactive,
    name,
    deep,
    copied,
    shallow,
    apply,
    originalName: original.profile.name,
    snapshot: computed(() => JSON.stringify(flatten(deep()), null, 2)),
    refCheck: isRef(deep),
    deepCheck: isDeepRef(deep),
    shallowCheck: isDeepRef(shallow),
    plainName: computed(() => unref(deep().profile().name)),
  }
}

export const stateTemplate = html` <div class="guide-demo">
  <div class="guide-filter">
    <label
      >New name<input
        type="text"
        maxlength="30"
        r-model="name"
        :value="name"
        :disabled="!interactive" /></label
    ><button type="button" @click="apply" :disabled="!interactive">
      Apply to all three
    </button>
  </div>
  <div class="api-comparison">
    <article class="directive-card">
      <span class="guide-kicker">REF / DEEP</span
      ><strong>{{ deep.profile.name }}</strong>
      <p>Nested properties are refs.</p>
    </article>
    <article class="directive-card">
      <span class="guide-kicker">CREF / COPY FIRST</span
      ><strong>{{ copied.profile.name }}</strong>
      <p>Original still says {{ originalName }}.</p>
    </article>
    <article class="directive-card">
      <span class="guide-kicker">SREF / SHALLOW</span
      ><strong>{{ shallow.profile.name }}</strong>
      <p>Replace the plain object to notify.</p>
    </article>
  </div>
  <dl class="directive-values">
    <div>
      <dt>isRef(deep) / isDeepRef(deep)</dt>
      <dd>{{ refCheck }} / {{ deepCheck }}</dd>
    </div>
    <div>
      <dt>isDeepRef(shallow) / unref(name)</dt>
      <dd>{{ shallowCheck }} / {{ plainName }}</dd>
    </div>
  </dl>
  <pre class="api-snapshot" r-text="snapshot"></pre>
</div>`
import { createApp, RegorConfig, useScope } from 'regor'
import { apiExamples } from './examples'

const element = document.getElementById('api-demo')
const name = element?.dataset.example
if (element && name && Object.hasOwn(apiExamples, name)) {
  const example = apiExamples[name as keyof typeof apiExamples]
  const scope = useScope<object>(() => example.create(true))
  const config =
    'config' in scope.context && scope.context.config instanceof RegorConfig
      ? scope.context.config
      : undefined
  createApp(scope, { element, template: example.template }, config)
}

Change the name and apply it. Inspect the nested values, ref checks, and flattened snapshot.

Usage

Getting the Ref Value

You can access the value of the ref object using two methods:

  1. refObj.value: Accesses the value directly.
  2. refObj(): Invokes the ref object to retrieve its value.

Setting the Ref Value

To update the value of a ref object, you have two options:

  1. refObj.value = newValue: Sets the value directly.
  2. refObj(newValue): Invokes the ref object with the new value to update it.

Parameters

  • value (optional): Any value that you want to convert into a ref object. The function supports several input types:

    • Basic types such as numbers, strings, booleans, Date etc.
    • ref objects.
    • objects
    • Array, Map, Set.
    • null or undefined.

Return Value

The ref function returns a ref object representing the input value and its nested properties. The specific type of the returned ref object depends on the input value's type.

Deep conversion changes the input

ref converts the supplied structure in place. Choose cref when you need a copied structure.

Notes

  • Certain types such as Node, Date, RegExp, Promise, and Error are not recursively converted into ref objects. They are treated as-is and returned as the value of the ref object.
  • Arrays and objects are recursively traversed to convert their nested properties into ref objects.
  • Arrays and objects are converted in place. Use cref when you need a copied deep ref without mutating the original object graph during initial conversion.
  • Symbols are not converted into ref objects, and the original symbols are preserved in the resulting ref object.
  • Observers can be attached to the ref object to be notified of changes to its value.
  • Every ref is an sref, but not every sref is a ref.

Example

import { ref } from 'regor'

interface Address {
  city: string
  state: string
}

interface User {
  name: string
  age: number
  address?: Address
}

const initialValue: User = {
  name: 'John',
  age: 30,
  address: {
    city: 'New York',
    state: 'NY',
  },
}

// create ref from initialValue.
// ref call replaces initial value's nested properties with ref objects recursively in place.
const myRef = ref<User>(initialValue) // returned type is Ref<User>

// Accessing the ref value using function call
console.log(myRef()) // Outputs the initial value

// Accessing the ref value using value getter
console.log(myRef.value) // Outputs the initial value

// Updating the ref value
myRef().name('Alice') // Modifying the ref value using function call
console.log(myRef().name()) // Outputs 'Alice'

// Updating the ref value using value using setter
myRef().name.value = 'Alice' // Modifying the ref value
console.log(myRef().name.value) // Outputs 'Alice'

myRef(
  ref({
    name: 'Alice',
    age: 35,
  }),
) // Invoking the ref with a new value
console.log(myRef().age()) // Outputs 35

See Also

Related APIs and guides Continue with the references connected to ref.

Back to the API list