DocsBlog
  • 1.1.2

  • light

    dark

    system

    Switch mode
  • Cerberus

    Acheron

    Elysium

Get Started
Components
Data Grid
Signals
Styling
Theming

Get Started

OverviewReactivityData FetchingStores

Primitives

createSignalcreateQuerycreateMutationcreateComputedcreateEffectcreateStoreContextbatch

Hooks

useQueryuseMutationuseReaduseSignal

Components

ReactiveText

On this page

  • Edit this page on Github

Signals Reactivity

Learn the fundamentals of fine-grained reactivity with signals.

  • source

Introduction

Reactivity powers the interactivity in React applications. This programming paradigm refers to a system's ability to respond to changes in data or state automatically. In React, this is natively built into the JSX render engine which means that when state changes, React re-renders any component that either defines or consumes it.

Cerberus Signals remove that constraint and provide a way to control to define and consume state without causing re-renders when updates happen.

This example shows the diversity of just one of the APIs the signals library provide:


Here the Demo component will re-render only on updates. However, the ReactiveText component will never re-render on updates to ensure fine-grained reactivity.

This is just one of many ways to achieve fine-grained reactivity with Cerberus Signals.

Reactive Principles

There are two core elements in a reactive system: Signals and Subscribers.

Signals

Signals serve as core elements in reactive systems, playing an important role in data management and system responsiveness. They are responsible for storing and managing data, as well as triggering updates across the system.

This is done through the use of accessors (a.k.a. getters) and setters.


  • Accessor: A function responsible for getting the current value of the signal. You call a getter to access the data stored in a signal within a component.
  • Setter: The function used to modify a signal's value. To trigger reactive updates across an application, you call a setter to update the value of a signal.

There are two ways to create signals:

  • createSignal: create signals outside of components in any scenario
  • useSignal: create signals inside of components

Subscribers

Subscribers are the other core element in reactive systems. They are responsible for tracking changes in signals and updating the system accordingly. They are automated responders that keep the system up-to-date with the latest data changes.

Most importantly: this lives outside of the React render engine

This enables Cerberus Signals to allow creating global, local, external/local component state updates without affecting the VDOM renders.

Subscribers work based on two main actions:

  • Observation: At their core, subscribers observe signals. This keeps the subscriber primed to pick up on any changes to the signal they are tracking.
  • Response: When a signal changes, the subscriber is notified. This triggers the subscriber to respond to the change in the signal. This can involve tasks like updating the UI or calling external functions.

There are multiple APIs that subscribe to signals:

  • createEffect: watch for state updates without affecting the React lifecycle
  • batch: batch signal updates
  • Any query or query related API

Synchronous Reactivity

Synchronous reactivity is Cerberus' default reactivity mode, where a system responds to changes in a direct and linear fashion. When a signal changes, any corresponding subscribers are immediately updated in an ordered manner.

With synchronous reactivity, the system is able to respond to changes in a predictable manner. This is useful in scenarios where the order of updates is important. For example, if a subscriber depends on another signal, it is important that the subscriber is updated after the signal it depends on.


In this example, the double signal will always be updated after count due to synchronous reactivity. This ensures that double is always up-to-date with the latest value of count.

0

0
Copy
'use client'

import { HStack } from '@/styled-system/jsx'
import { Button } from '@cerberus/react'
import { ReactiveText, useSignal } from '@cerberus/signals'

export function BasicDemo() {
  const [count, setCount, getCount] = useSignal<number>(0)

  return (
    <HStack gap="md">
      <Button onClick={() => setCount(getCount() + 1)}>Increment</Button>
      <p>{count}</p>

      {/* Not re-rendered - but the text value is updated */}
      <ReactiveText data={getCount} />
    </HStack>
  )
}
import { createSignal } from '@cerberus/signals'

const [_count, _setCount] = createSignal<number>(0)
//     ^ getter  ^ setter
import { createEffect, createSignal } from '@cerberus/signals'

const [count, _setCount] = createSignal(0)
const [_double, setDouble] = createSignal(0)

createEffect(() => {
  setDouble(count() * 2)
})