useScope

Create a context with owned effects and lifecycle cleanup.

useScopeLifecycle and Scope

Create a context with owned effects and lifecycle cleanup.

Overview

The useScope function allows you to create a scope for an app or composable, enabling you to manage initialization and cleanup tasks specific to that scope. Scopes are useful for organizing and encapsulating logic within your components.

Components are always created in scope using defineComponent function.

Try it live

Setup and cleanup with an ownerLive API
Child is unmounted
0Total ticks
0Mounts
0Cleanups

Ready. Mount the ticker to start its interval.

Unmount the child: the tick count stops. Remount it: a fresh interval starts. The parent keeps the totals.

import { defineComponent, html, onMounted, onUnmounted, ref } from 'regor'

export function createLifecycle(interactive = false) {
  const active = ref(false)
  const toggle = () => active(!active())
  const ticks = ref(0)
  const starts = ref(0)
  const cleanups = ref(0)
  const lastEvent = ref('Ready. Mount the ticker to start its interval.')
  const SessionTicker = defineComponent(
    html`<p class="guide-ticker">
      Interval running <span aria-hidden="true">●</span>
    </p>`,
    {
      context: () => {
        let timer: ReturnType<typeof setInterval> | undefined
        onMounted(() => {
          starts(starts() + 1)
          lastEvent('onMounted → start interval')
          timer = setInterval(() => ticks(ticks() + 1), 500)
        })
        onUnmounted(() => {
          clearInterval(timer)
          cleanups(cleanups() + 1)
          lastEvent('onUnmounted → clear interval')
        })
        return {}
      },
    },
  )
  // No child is mounted during static rendering, so the build creates no timer.
  return {
    interactive,
    active,
    toggle,
    ticks,
    starts,
    cleanups,
    lastEvent,
    components: { SessionTicker },
  }
}

export const lifecycleTemplate = html` <div class="guide-demo">
  <div class="guide-session-bar">
    <button type="button" @click="toggle" :disabled="!interactive">
      {{ active ? 'Unmount ticker' : 'Mount ticker' }}</button
    ><span>{{ active ? 'Child is mounted' : 'Child is unmounted' }}</span>
  </div>
  <SessionTicker r-if="active" />
  <div class="guide-metrics">
    <div><output>{{ ticks }}</output><span>Total ticks</span></div>
    <div><output>{{ starts }}</output><span>Mounts</span></div>
    <div><output>{{ cleanups }}</output><span>Cleanups</span></div>
  </div>
  <p class="guide-event" role="status">{{ lastEvent }}</p>
  <p class="guide-hint">
    Unmount the child: the tick count stops. Remount it: a fresh interval
    starts. The parent keeps the totals.
  </p>
</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)
}

Mount the child ticker, then unmount it. The parent keeps totals while the child releases its interval.

Usage

Creating a Scope

To create a scope for an app or composable, call the useScope function and pass a context function as its argument. The context function is used to set up the scope's context and register initialization and cleanup tasks.


import { createApp, defineComponent, html, useScope, onUnmounted, ref, computed, watchEffect } from 'regor'

const userRow = defineComponent(html`<div></div>`, {
  context: () => {
    // Register an onUnmounted callback
    onUnmounted(() => {
      // Perform cleanup  tasks
      console.log('Component is unmounted!')
    })
    return {}
  },
})

createApp(
  useScope(() => {
    // Register an onUnmounted callback
    onUnmounted(() => {
      // Perform cleanup  tasks
      console.log('App is unmounted!')
    })
    return {}
  }),
)

const ref1 = ref(5)
const scope = useScope(() => {
    watchEffect(() => {
        // do some reactive tasks
    })
    const computedValue = computed(() => ref1() * 2)
    return { computedValue }
  })

scope.unmount() // Registered observers by watchEffect and computed are cleaned up

Cleanup and Unmounting

Scopes are especially useful for defining cleanup behavior when a component is unmounted. You can register onUnmounted callbacks within the scope to handle cleanup tasks.

Parameters

  • context (required): A function that sets up the context and registers initialization and cleanup tasks for the scope.

Return Value

  • An object containing the following properties:
    • context: The context of the scope that can be used within the component or composable.
    • unmount: A function that, when called, triggers the cleanup tasks registered within the scope. It is automatically being called when the app or component is unmounted. It can be manually caled for custom scopes.
Register resources inside their owner’s scope

Use useScope around app setup. A component’s context factory already runs in a component scope.

Notes

  • Scopes help you encapsulate and organize component-specific logic, making it easier to manage initialization and cleanup tasks.

  • Multiple scopes can be created within a single component or composable to isolate different sets of tasks.

See Also

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

Back to the API list