ref
Create writable state and recursively convert nested object and array fields to refs.
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 live
Nested properties are refs.
Original still says Ada.
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:
refObj.value: Accesses the value directly.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:
refObj.value = newValue: Sets the value directly.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.
nullorundefined.
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.
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
crefwhen 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
refis ansref, but not everysrefis aref.
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