flatten

Unwrap a nested reactive structure into plain values.

flattenUtilities

Unwrap a nested reactive structure into plain values.

Overview

The flatten function recursively traverses a nested structure, such as an object, array, set, or map, and returns a flattened version of the structure. This means that it removes any nested references and produces a structure containing no refs.

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

Flattening Nested Structures

To flatten a nested structure, simply pass the reference to the flatten function. It will return a new structure with all nested references removed.

import { flatten, ref } from 'regor'

const nestedData = {
  name: 'John',
  age: ref(30),
  hobbies: ['reading', 'swimming', ref('drawing')],
}

const flattenedData = flatten(nestedData)

console.log(flattenedData)
// Outputs: { name: 'John', age: 30, hobbies: [ 'reading', 'swimming', 'drawing' ] }

Parameters

  • reference: The nested structure (object, array, set, map) that you want to flatten. It can contain nested refs, which will be resolved during flattening.

Return Value

  • The flatten function returns a new structure that is a flattened version of the input reference. Any nested refs within the structure are resolved, resulting in a single-level structure.
Flatten when crossing a plain-data boundary

Use a plain snapshot for serialization or external code that should not receive refs.

Notes

  • The flatten function recursively flattens nested structures, including arrays, sets, maps, and objects.

  • If the input reference contains refs, they are automatically unrefed during flattening, and their values are included in the flattened structure.

  • Circular references within the input reference are not supported, and attempting to flatten such structures may result in unexpected behavior.

Example

import { flatten, ref } from 'regor'

const nestedData = {
  name: 'John',
  age: ref(30),
  hobbies: ['reading', 'swimming', ref('drawing')],
}

const flattenedData = flatten(nestedData)

console.log(flattenedData)
// Outputs: { name: 'John', age: 30, hobbies: [ 'reading', 'swimming', 'drawing' ] }

See Also

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

Back to the API list