DocsBlog
  • 1.3.0

  • light

    dark

    system

    Switch mode
  • Cerberus

    Acheron

    Elysium

Get Started
Components
Data Grid
Signals
Styling
Theming

Get Started

OverviewReactivityData FetchingStores

Primitives

createSignalcreateQueryNewcreateMutationNewcreateComputedcreateEffectcreateStoreContextbatchonCleanupNewuntrackNew

Hooks

useQueryNewuseMutationuseReaduseSignaluseStoreNew

Components

ReactiveText

On this page

Loading...

Loading...

Loading...

Loading...

Untrack Signals

Learn how to read signals without subscribing to updates.

  • source
import { untrack } from '@cerberus/signals'

Usage

The untrack primitive allows you to read the current value of a signal inside a reactive context (like createEffect, createComputed, or a React render phase) without subscribing to that signal.

This prevents unwanted re-evaluations, React infinite loops, and over-subscribing to state changes.

In this example, we update a signal and show the latest result (tracked) and what the untracked version is.

When to use

By default, any signal read inside a tracking context will automatically bind to it. When that signal updates, the context re-runs. However, there are common scenarios where you only want to read the data, not react to it:

  1. Logging or Analytics: You want to fire an analytics event when userSignal changes, but you need to include the themeSignal value in the payload without re-firing the event when the theme changes.
  2. Preventing Infinite Loops: You need to conditionally initialize or mutate state based on the current value of a cache, without accidentally subscribing the surrounding component to the cache's internal lifecycle.
  3. Optimizing Component Renders: In React integrations, bypassing unnecessary subscriptions keeps your component from re-rendering O(1) updates that don't affect the DOM.

Best Practices

  • Keep it synchronous: untrack only disables tracking for the synchronous execution of the callback. If you use await inside the callback, signals read after the await might resume tracking depending on the environment context.
  • Keep it targeted: Wrap only the specific signal reads you want to isolate. Wrapping entire large blocks of logic can lead to accidentally missing subscriptions you actually intended to track.

API

untrack accepts an Accessor signal and returns the unsubscribed value at the time of calling.

Copy
'use client'

import { HStack, Stack } from '@/styled-system/jsx'
import { Button, Text } from '@cerberus/react'
import { ReactiveText, untrack, useStore } from '@cerberus/signals'
import { useEffect } from 'react'
import { createRenderStore } from '../render-store'

export function BasicDemo() {
  const store = useStore(createRenderStore)

  const increment = () => {
    store.setCount((prev) => prev + 1)
  }

  useEffect(() => {
    store.startCounter()
    return () => store.onUnmount()
  }, [store])

  store.trackRenders()

  return (
    <HStack justify="space-between" w="3/4">
      <Button onClick={increment}>Increment</Button>

      <Stack>
        <Text>
          Count: <ReactiveText data={store.count} />
        </Text>
        <Text>Untracked: {untrack(store.count)}</Text>
        <Text>
          Render Count: <ReactiveText data={store.renderCount} />
        </Text>
      </Stack>
    </HStack>
  )
}

Count: 0

Untracked: 0

Render Count: 1

On this page

  • Usage
  • When to use
  • Best Practices
  • API
  • Edit this page on Github