ReactiveVar struct

Fields:

  • value (T)
  • listeners ([]func(T))

NewReactiveVar function

Parameters:

  • initial T

Returns:

  • *ReactiveVar[T]
Show/Hide Function Body
{
	return &ReactiveVar[T]{
		value: initial,
	}
}

ReactiveString type

ReactiveString is a convenience alias for ReactiveVar[string].

Type Definition:

ReactiveVar[string]

Computed struct

Computed represents a derived state value based on other store keys.

It holds the target key for the computed value, the list of dependencies

and the function used to calculate the value.

Fields:

  • key (string)
  • deps ([]string)
  • compute (func(map[string]any) any)
  • lastDeps (map[string]any)

Methods:

Key

Key returns the store key associated with the computed value.


Returns:
  • string

Show/Hide Method Body
{ return c.key }

Deps

Deps returns the list of keys this computed value depends on.


Returns:
  • []string

Show/Hide Method Body
{ return c.deps }

Evaluate

Evaluate executes the compute function using the provided state and returns

the result.


Parameters:
  • state map[string]any

Returns:
  • any

Show/Hide Method Body
{
	return c.compute(state)
}

NewComputed function

NewComputed creates a new Computed value.

Parameters:

  • key string
  • deps []string
  • compute func(map[string]any) any

Returns:

  • *Computed
Show/Hide Function Body
{
	return &Computed{key: key, deps: deps, compute: compute}
}

Watcher struct

Watcher represents a callback that reacts to changes on specific store keys.

When any of the dependencies change, the associated function is triggered.

Fields:

  • deps ([]string)
  • run (func(map[string]any))
  • deep (bool)
  • immediate (bool)

Methods:

Deps

Deps returns the list of keys the watcher observes.


Returns:
  • []string

Show/Hide Method Body
{ return w.deps }

Run

Run triggers the watcher with the provided state.


Parameters:
  • state map[string]any

Show/Hide Method Body
{ w.run(state) }

WatcherOption type

WatcherOption configures optional watcher behaviour.

Type Definition:

func(*Watcher)

WatcherDeep function

WatcherDeep enables deep watching of nested keys.

Returns:

  • WatcherOption

References:

Show/Hide Function Body
{ return func(w *Watcher) { w.deep = true } }

WatcherImmediate function

WatcherImmediate triggers the watcher immediately after registration.

Returns:

  • WatcherOption

References:

Show/Hide Function Body
{ return func(w *Watcher) { w.immediate = true } }

NewWatcher function

NewWatcher creates a new Watcher.

Parameters:

  • deps []string
  • run func(map[string]any)
  • opts ...WatcherOption

Returns:

  • *Watcher
Show/Hide Function Body
{
	w := &Watcher{deps: deps, run: run}
	for _, opt := range opts {
		opt(w)
	}
	return w
}

TestSignalHookAndSnapshot function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	var gotID int
	var gotVal any
	SignalHook = func(id int, v any) {
		gotID = id
		gotVal = v
	}
	s := NewSignal(1)
	s.Set(2)
	if gotID != s.id || gotVal != 2 {
		t.Fatalf("hook not invoked")
	}
	snap := SnapshotSignals()
	if v, ok := snap[s.id]; !ok || v != 2 {
		t.Fatalf("snapshot missing or incorrect, got %v", snap)
	}
}

Context type

Context is an alias of context.Context used by Actions.

This allows the API to remain stable if a custom context is needed later.

Type Definition:

context.Context

Action type

Action represents a unit of work executed with a Context.

It returns an error if the action fails.

Type Definition:

func(ctx Context) error

Dispatch function

Dispatch executes the given Action with the provided context.

If the action is nil it is a no-op and nil is returned.

Parameters:

  • ctx Context
  • a Action

Returns:

  • error

References:

Show/Hide Function Body
{
	if a == nil {
		return nil
	}
	return a(ctx)
}

UseAction function

UseAction binds an Action to a Context and returns a function

that executes the action when invoked. It can be used in places

that expect a simple callback.

Parameters:

  • ctx Context
  • a Action

Returns:

  • func() error

References:

Show/Hide Function Body
{
	return func() error {
		return Dispatch(ctx, a)
	}
}

TestComputedStability function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewStore("test")
	s.Set("a", 1)

	evalCount := 0
	c := NewComputed("double", []string{"a"}, func(m map[string]any) any {
		evalCount++
		return m["a"].(int) * 2
	})
	s.RegisterComputed(c)

	if evalCount != 1 {
		t.Fatalf("expected 1 evaluation, got %d", evalCount)
	}
	if v := s.Get("double"); v != 2 {
		t.Fatalf("expected computed value 2, got %v", v)
	}

	// Setting dependency to same value should not re-evaluate
	s.Set("a", 1)
	if evalCount != 1 {
		t.Fatalf("computed re-evaluated without dependency change")
	}

	// Setting unrelated key should not re-evaluate
	s.Set("b", 5)
	if evalCount != 1 {
		t.Fatalf("computed re-evaluated for unrelated key")
	}

	// Changing dependency should trigger re-evaluation
	s.Set("a", 3)
	if evalCount != 2 {
		t.Fatalf("expected second evaluation after dependency change, got %d", evalCount)
	}
	if v := s.Get("double"); v != 6 {
		t.Fatalf("expected computed value 6, got %v", v)
	}
}

TestMapHelpers function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewStore("test")
	s.Set("count", 2)

	Map(s, "double", "count", func(v int) int { return v * 2 })

	if v := s.Get("double"); v != 4 {
		t.Fatalf("expected 4, got %v", v)
	}

	s.Set("count", 3)
	if v := s.Get("double"); v != 6 {
		t.Fatalf("expected 6 after update, got %v", v)
	}

	s.Set("first", "Ada")
	s.Set("last", "Lovelace")

	Map2(s, "fullName", "first", "last", func(f, l string) string {
		return strings.TrimSpace(f + " " + l)
	})

	if v := s.Get("fullName"); v != "Ada Lovelace" {
		t.Fatalf("expected full name Ada Lovelace, got %v", v)
	}

	s.Set("last", "Hopper")
	if v := s.Get("fullName"); v != "Ada Hopper" {
		t.Fatalf("expected full name Ada Hopper, got %v", v)
	}
}

TestExposeUpdateStoreBool function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	ExposeUpdateStore()
	js.Call("goUpdateStore", "mod", "test", "flag", true)
	store := GlobalStoreManager.GetStore("mod", "test")
	if store == nil {
		t.Fatalf("store not created")
	}
	v, ok := store.Get("flag").(bool)
	if !ok || !v {
		t.Fatalf("expected true bool, got %#v", store.Get("flag"))
	}
}

loadPersistedState function

loadPersistedState is a no-op on non-JS platforms.

Parameters:

  • key string

Returns:

  • map[string]any
Show/Hide Function Body
{ return nil }

saveState function

saveState is a no-op on non-JS platforms.

Parameters:

  • key string
  • state map[string]any
Show/Hide Function Body
{}

capturingLogger struct

Fields:

  • logs ([]string)

Implements:

  • Logger from state

Methods:

Debug


Parameters:
  • format string
  • args ...any

Show/Hide Method Body
{
	cl.logs = append(cl.logs, fmt.Sprintf(format, args...))
}

TestOnChangeLoggingWithDevTools function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	// capture and restore global state
	oldLogger := logger
	cl := &capturingLogger{}
	SetLogger(cl)
	defer SetLogger(oldLogger)

	oldGSM := GlobalStoreManager
	GlobalStoreManager = &StoreManager{modules: make(map[string]map[string]*Store)}
	defer func() { GlobalStoreManager = oldGSM }()

	// store without devtools should not log
	s1 := NewStore("s1")
	s1.OnChange("a", func(any) {})
	if len(cl.logs) != 0 {
		t.Fatalf("expected no logs for store without devtools, got %v", cl.logs)
	}

	// store with devtools should log
	cl.logs = nil
	s2 := NewStore("s2", WithDevTools())
	s2.OnChange("a", func(any) {})
	if len(cl.logs) == 0 {
		t.Fatalf("expected logs for store with devtools enabled")
	}
}

TestStoreUndoRedo function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewStore("hist", WithHistory(10))
	s.Set("count", 1)
	s.Set("count", 2)
	if v := s.Get("count"); v != 2 {
		t.Fatalf("expected 2, got %v", v)
	}
	s.Undo()
	if v := s.Get("count"); v != 1 {
		t.Fatalf("expected 1 after undo, got %v", v)
	}
	s.Redo()
	if v := s.Get("count"); v != 2 {
		t.Fatalf("expected 2 after redo, got %v", v)
	}
}

TestStoreHistoryLimit function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewStore("limit", WithHistory(2))
	s.Set("val", 1)
	s.Set("val", 2)
	s.Set("val", 3)
	s.Set("val", 4)
	// history limit 2 means only last two changes are tracked
	s.Undo() // 4 -> 3
	if v := s.Get("val"); v != 3 {
		t.Fatalf("expected 3 after first undo, got %v", v)
	}
	s.Undo() // 3 -> 2
	if v := s.Get("val"); v != 2 {
		t.Fatalf("expected 2 after second undo, got %v", v)
	}
	s.Undo() // no effect, history exhausted
	if v := s.Get("val"); v != 2 {
		t.Fatalf("expected 2 after exhausting history, got %v", v)
	}
}

TestRedoClearedOnNewMutation function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewStore("redo", WithHistory(10))
	s.Set("a", 1)
	s.Set("a", 2)
	s.Undo()      // a ->1, future has mutation 1->2
	s.Set("a", 3) // new mutation should clear redo stack
	s.Redo()      // should do nothing
	if v := s.Get("a"); v != 3 {
		t.Fatalf("expected 3 after redo with cleared history, got %v", v)
	}
}

ExposeUpdateStore function

ExposeUpdateStore exposes a JS function to update store values.

Show/Hide Function Body
{
	js.Set("goUpdateStore", js.FuncOf(func(this js.Value, args []js.Value) any {
		if len(args) < 4 {
			return nil
		}
		module := args[0].String()
		storeName := args[1].String()
		key := args[2].String()

		var newValue any
		switch args[3].Type() {
		case js.TypeString:
			newValue = args[3].String()
		case js.TypeBoolean:
			newValue = args[3].Bool()
		case js.TypeNumber:
			newValue = args[3].Float()
		default:
			newValue = args[3]
		}

		store := GlobalStoreManager.GetStore(module, storeName)
		if store == nil {
			store = NewStore(storeName, WithModule(module))
		}
		store.Set(key, newValue)
		return nil
	}))
}

loadPersistedState function

loadPersistedState retrieves persisted state from localStorage.

Parameters:

  • key string

Returns:

  • map[string]any
Show/Hide Function Body
{
	ls := js.LocalStorage()
	if !ls.Truthy() {
		return nil
	}
	item := ls.Call("getItem", key)
	if item.Type() != js.TypeString {
		return nil
	}
	var state map[string]any
	if err := json.Unmarshal([]byte(item.String()), &state); err != nil {
		return nil
	}
	return state
}

saveState function

saveState persists the store state in localStorage.

Parameters:

  • key string
  • state map[string]any
Show/Hide Function Body
{
	ls := js.LocalStorage()
	if !ls.Truthy() {
		return
	}
	data, err := json.Marshal(state)
	if err != nil {
		return
	}
	ls.Call("setItem", key, string(data))
}

registerSignal function

Parameters:

  • v any

Returns:

  • int
Show/Hide Function Body
{
	sigMu.Lock()
	id := nextSigID
	nextSigID++
	sigValues[id] = v
	sigMu.Unlock()
	return id
}

updateSignal function

Parameters:

  • id int
  • v any
Show/Hide Function Body
{
	sigMu.Lock()
	sigValues[id] = v
	sigMu.Unlock()
	if SignalHook != nil {
		SignalHook(id, v)
	}
}

SnapshotSignals function

SnapshotSignals returns a copy of all tracked signals.

Returns:

  • map[int]any
Show/Hide Function Body
{
	sigMu.Lock()
	defer sigMu.Unlock()
	snap := make(map[int]any, len(sigValues))
	for k, v := range sigValues {
		snap[k] = v
	}
	return snap
}

registerSignal function

Parameters:

  • v any

Returns:

  • int
Show/Hide Function Body
{ return 0 }

updateSignal function

Parameters:

  • id int
  • v any
Show/Hide Function Body
{}

SnapshotSignals function

Returns:

  • map[int]any
Show/Hide Function Body
{ return nil }

TestDispatch function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	called := false
	a := Action(func(ctx Context) error {
		called = true
		return nil
	})
	if err := Dispatch(context.Background(), a); err != nil {
		t.Fatalf("dispatch returned error: %v", err)
	}
	if !called {
		t.Fatalf("action was not executed")
	}
}

TestUseAction function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	called := false
	a := Action(func(ctx Context) error {
		called = true
		return nil
	})
	fn := UseAction(context.Background(), a)
	if err := fn(); err != nil {
		t.Fatalf("use action returned error: %v", err)
	}
	if !called {
		t.Fatalf("action not executed via UseAction")
	}
}

TestSignalEffect function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	a := NewSignal(0)
	b := NewSignal(0)

	var runs int
	stop := Effect(func() func() {
		_ = a.Get()
		runs++
		return nil
	})
	defer stop()

	b.Set(1)
	if runs != 1 {
		t.Fatalf("effect ran on unrelated signal change")
	}
	a.Set(1)
	if runs != 2 {
		t.Fatalf("effect did not rerun on dependent signal change")
	}
}

TestEffectCleanup function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	s := NewSignal(0)
	var cleans int
	stop := Effect(func() func() {
		_ = s.Get()
		return func() { cleans++ }
	})

	s.Set(1)
	if cleans != 1 {
		t.Fatalf("cleanup not called before rerun, got %d", cleans)
	}
	stop()
	if cleans != 2 {
		t.Fatalf("cleanup not called on stop, got %d", cleans)
	}
}

Logger interface

Methods:

Debug


Parameters:
  • format string
  • args ...any

defaultLogger struct

Implements:

  • Logger from state

Methods:

Debug


Parameters:
  • format string
  • args ...any

Show/Hide Method Body
{ log.Printf(format, args...) }

SetLogger function

Parameters:

  • l Logger

References:

Show/Hide Function Body
{ logger = l }

StoreOption type

StoreOption configures optional behaviour for a Store during creation.

Type Definition:

func(*Store)

WithModule function

WithModule namespaces a store under the provided module.

Parameters:

  • module string

Returns:

  • StoreOption

References:

Show/Hide Function Body
{ return func(s *Store) { s.module = module } }

WithPersistence function

WithPersistence enables localStorage persistence for the store.

Returns:

  • StoreOption

References:

Show/Hide Function Body
{ return func(s *Store) { s.persist = true } }

WithDevTools function

WithDevTools enables logging of state mutations for development.

Returns:

  • StoreOption

References:

Show/Hide Function Body
{ return func(s *Store) { s.devTools = true } }

WithHistory function

WithHistory enables mutation history with the provided limit.

The limit controls how many past mutations are retained for undo/redo.

Parameters:

  • limit int

Returns:

  • StoreOption

References:

Show/Hide Function Body
{
	return func(s *Store) {
		if limit > 0 {
			s.historyLimit = limit
		}
	}
}

Store struct

Fields:

  • module (string)
  • name (string)
  • state (map[string]any)
  • listeners (map[string]map[int]func(any))
  • listenerID (int)
  • computeds (map[string]*Computed)
  • watchers ([]*Watcher)
  • persist (bool)
  • devTools (bool)
  • history ([]*mutation)
  • future ([]*mutation)
  • historyLimit (int)
  • suppressHistory (bool)

Methods:

Module

Module reports the module namespace of the store.


Returns:
  • string

Show/Hide Method Body
{ return s.module }

Name

Name returns the store name within its module namespace.


Returns:
  • string

Show/Hide Method Body
{ return s.name }

Snapshot

Snapshot copies the current state of the store.


Returns:
  • map[string]any

Show/Hide Method Body
{
	snap := make(map[string]any, len(s.state))
	for k, v := range s.state {
		snap[k] = v
	}
	return snap
}

storageKey


Returns:
  • string

Show/Hide Method Body
{ return s.module + ":" + s.name }

Set


Parameters:
  • key string
  • value any

Show/Hide Method Body
{
	old := s.state[key]
	s.state[key] = value
	if s.historyLimit > 0 && !s.suppressHistory {
		s.history = append(s.history, &mutation{key: key, previous: old, next: value})
		if len(s.history) > s.historyLimit {
			s.history = s.history[len(s.history)-s.historyLimit:]
		}
		s.future = nil
	}
	if s.devTools {
		logger.Debug("%s/%s -> %s: %v", s.module, s.name, key, value)
	}
	if StoreHook != nil {
		StoreHook(s.module, s.name, key, value)
	}
	if listeners, exists := s.listeners[key]; exists {
		for _, listener := range listeners {
			listener(value)
		}
	}
	s.evaluateDependents(key)
	if s.persist {
		saveState(s.storageKey(), s.state)
	}
}

Get


Parameters:
  • key string

Returns:
  • any

Show/Hide Method Body
{
	if s.devTools {
		logger.Debug("Getting %s from %s/%s", key, s.module, s.name)
	}
	return s.state[key]
}

Undo

Undo reverts the last mutation recorded in the store's history.


Show/Hide Method Body
{
	if len(s.history) == 0 {
		return
	}
	m := s.history[len(s.history)-1]
	s.history = s.history[:len(s.history)-1]
	s.suppressHistory = true
	s.Set(m.key, m.previous)
	s.suppressHistory = false
	s.future = append(s.future, m)
}

Redo

Redo reapplies the last mutation that was undone.


Show/Hide Method Body
{
	if len(s.future) == 0 {
		return
	}
	m := s.future[len(s.future)-1]
	s.future = s.future[:len(s.future)-1]
	s.suppressHistory = true
	s.Set(m.key, m.next)
	s.suppressHistory = false
	s.history = append(s.history, m)
	if s.historyLimit > 0 && len(s.history) > s.historyLimit {
		s.history = s.history[len(s.history)-s.historyLimit:]
	}
}

OnChange


Parameters:
  • key string
  • listener func(any)

Returns:
  • func()

Show/Hide Method Body
{
	if s.listeners[key] == nil {
		s.listeners[key] = make(map[int]func(any))
	}
	s.listenerID++
	id := s.listenerID
	s.listeners[key][id] = listener

	if s.devTools {
		logger.Debug("------")
		for moduleName, stores := range GlobalStoreManager.modules {
			for storeName, store := range stores {
				logger.Debug("Store: %s/%s", moduleName, storeName)
				for key, value := range store.state {
					logger.Debug("  %s: %v", key, value)
				}
			}
		}
		logger.Debug("------")
	}

	return func() {
		delete(s.listeners[key], id)
	}
}

RegisterComputed

RegisterComputed registers a computed value on the store. The computed value

is evaluated immediately and whenever one of its dependencies changes.


Parameters:
  • c *Computed

Show/Hide Method Body
{
	s.computeds[c.Key()] = c
	val := c.Evaluate(s.state)
	s.state[c.Key()] = val
	c.lastDeps = snapshotDeps(s.state, c.Deps())
}

RegisterWatcher

RegisterWatcher registers a watcher that triggers when any of its

dependencies change. If the dependency list is empty the watcher is triggered

on every state update. It returns a function that removes the watcher.


Parameters:
  • w *Watcher

Returns:
  • func()

Show/Hide Method Body
{
	s.watchers = append(s.watchers, w)
	if w.immediate {
		w.Run(s.state)
	}

	return func() {
		for i, watcher := range s.watchers {
			if watcher == w {
				s.watchers = append(s.watchers[:i], s.watchers[i+1:]...)
				break
			}
		}
	}
}

evaluateDependents

evaluateDependents re-evaluates computed values and triggers watchers for a

given key.


Parameters:
  • key string

Show/Hide Method Body
{
	for _, c := range s.computeds {
		if contains(c.Deps(), key) {
			current := snapshotDeps(s.state, c.Deps())
			if c.lastDeps == nil || !reflect.DeepEqual(current, c.lastDeps) {
				val := c.Evaluate(s.state)
				s.state[c.Key()] = val
				c.lastDeps = current
				if listeners, exists := s.listeners[c.Key()]; exists {
					for _, listener := range listeners {
						listener(val)
					}
				}
				// propagate to computeds/watchers depending on this key
				s.evaluateDependents(c.Key())
			}
		}
	}
	for _, w := range s.watchers {
		deps := w.Deps()
		if len(deps) == 0 {
			w.Run(s.state)
			continue
		}
		for _, dep := range deps {
			if w.deep {
				if pathMatches(key, dep) {
					w.Run(s.state)
					break
				}
			} else {
				if key == dep {
					w.Run(s.state)
					break
				}
			}
		}
	}
}

mutation struct

Fields:

  • key (string)
  • previous (any)
  • next (any)

StoreManager struct

Fields:

  • mu (sync.RWMutex)
  • modules (map[string]map[string]*Store)

Methods:

NewStore


Parameters:
  • name string
  • opts ...StoreOption

Returns:
  • *Store

Show/Hide Method Body
{
	store := &Store{
		module:    "default",
		name:      name,
		state:     make(map[string]any),
		listeners: make(map[string]map[int]func(any)),
		computeds: make(map[string]*Computed),
	}
	for _, opt := range opts {
		opt(store)
	}

	sm.RegisterStore(store.module, name, store)

	if store.persist {
		if state := loadPersistedState(store.storageKey()); state != nil {
			store.state = state
		}
	}

	return store
}

RegisterStore


Parameters:
  • module string
  • name string
  • store *Store

Show/Hide Method Body
{

	sm.mu.Lock()
	defer sm.mu.Unlock()

	if sm.modules[module] == nil {
		sm.modules[module] = make(map[string]*Store)
	}
	sm.modules[module][name] = store
}

GetStore


Parameters:
  • module string
  • name string

Returns:
  • *Store

Show/Hide Method Body
{

	sm.mu.RLock()
	defer sm.mu.RUnlock()

	if stores, ok := sm.modules[module]; ok {
		return stores[name]
	}
	return nil
}

UnregisterStore

UnregisterStore removes the store identified by module and name.

If the store or module does not exist, it is a no-op.


Parameters:
  • module string
  • name string

Show/Hide Method Body
{
	sm.mu.Lock()
	defer sm.mu.Unlock()
	if stores, ok := sm.modules[module]; ok {
		delete(stores, name)
		if len(stores) == 0 {
			delete(sm.modules, module)
		}
	}
}

Snapshot

Snapshot returns a deep copy of all registered stores and their states.


Returns:
  • map[string]map[string]map[string]any

Show/Hide Method Body
{
	snap := make(map[string]map[string]map[string]any)

	sm.mu.RLock()
	defer sm.mu.RUnlock()

	for module, stores := range sm.modules {
		snap[module] = make(map[string]map[string]any)
		for name, store := range stores {
			stateCopy := make(map[string]any)
			for k, v := range store.state {
				stateCopy[k] = v
			}
			snap[module][name] = stateCopy
		}
	}
	return snap
}

NewStoreManager function

NewStoreManager creates a standalone manager for isolating store instances.

Returns:

  • *StoreManager
Show/Hide Function Body
{
	return &StoreManager{modules: make(map[string]map[string]*Store)}
}

NewStore function

NewStore creates a new store with the given name and optional configuration.

By default stores are registered under the "default" module.

Parameters:

  • name string
  • opts ...StoreOption

Returns:

  • *Store
Show/Hide Function Body
{
	return GlobalStoreManager.NewStore(name, opts...)
}

Map function

Map registers a computed value derived from a single dependency using a

strongly typed mapping function. The mapping function receives the current

value of the dependency and its result is stored under the provided key. If

the dependency cannot be asserted to the expected type, the zero value of the

return type is used instead.

Parameters:

  • s *Store
  • key string
  • dep string
  • compute func(T) R
Show/Hide Function Body
{
	c := NewComputed(key, []string{dep}, func(m map[string]any) any {
		if v, ok := m[dep].(T); ok {
			return compute(v)
		}
		var zero R
		return zero
	})
	s.RegisterComputed(c)
}

Map2 function

Map2 registers a computed value derived from two dependencies. The mapping

function receives the current values of both dependencies and its result is

stored under the provided key. If any dependency fails type assertion the

zero value of the return type is used.

Parameters:

  • s *Store
  • key string
  • depA string
  • depB string
  • compute func(A, B) R
Show/Hide Function Body
{
	c := NewComputed(key, []string{depA, depB}, func(m map[string]any) any {
		a, okA := m[depA].(A)
		b, okB := m[depB].(B)
		if okA && okB {
			return compute(a, b)
		}
		var zero R
		return zero
	})
	s.RegisterComputed(c)
}

contains function

Parameters:

  • slice []string
  • item string

Returns:

  • bool
Show/Hide Function Body
{
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}

pathMatches function

Parameters:

  • key string
  • dep string

Returns:

  • bool
Show/Hide Function Body
{
	if key == dep {
		return true
	}
	if strings.HasPrefix(key, dep+".") {
		return true
	}
	if strings.HasPrefix(dep, key+".") {
		return true
	}
	return false
}

snapshotDeps function

Parameters:

  • state map[string]any
  • deps []string

Returns:

  • map[string]any
Show/Hide Function Body
{
	snap := make(map[string]any, len(deps))
	for _, d := range deps {
		snap[d] = state[d]
	}
	return snap
}

TestReactiveVarInt function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	rv := NewReactiveVar(0)
	var changed int
	rv.OnChange(func(v int) { changed = v })
	rv.Set(42)
	if got := rv.Get(); got != 42 {
		t.Fatalf("expected Get to return 42, got %d", got)
	}
	if changed != 42 {
		t.Fatalf("expected OnChange to fire with 42, got %d", changed)
	}
}

sample struct

Fields:

  • A (int)
  • B (string)

TestReactiveVarStruct function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	initial := sample{A: 1, B: "foo"}
	rv := NewReactiveVar(initial)
	var changed sample
	rv.OnChange(func(s sample) { changed = s })
	newVal := sample{A: 2, B: "bar"}
	rv.Set(newVal)
	if got := rv.Get(); !reflect.DeepEqual(got, newVal) {
		t.Fatalf("expected Get to return %v, got %v", newVal, got)
	}
	if !reflect.DeepEqual(changed, newVal) {
		t.Fatalf("expected OnChange to receive %v, got %v", newVal, changed)
	}
}

effect struct

effect represents a reactive computation registered via Effect.

Fields:

  • run (func() func())
  • deps ([]subscriber)
  • cleanup (func())

Methods:

runEffect


Show/Hide Method Body
{
	if e.cleanup != nil {
		e.cleanup()
		e.cleanup = nil
	}
	for _, dep := range e.deps {
		dep.remove(e)
	}
	e.deps = nil
	prev := currentEffect
	currentEffect = e
	e.cleanup = e.run()
	currentEffect = prev
}

stop


Show/Hide Method Body
{
	if e.cleanup != nil {
		e.cleanup()
		e.cleanup = nil
	}
	for _, dep := range e.deps {
		dep.remove(e)
	}
	e.deps = nil
}

subscriber interface

Methods:

remove


Parameters:
  • *effect

Signal struct

Signal holds a value of type T and tracks which effects depend on it.

Fields:

  • id (int)
  • value (T)
  • subs (map[*effect]struct{})

NewSignal function

NewSignal creates a new Signal with the given initial value.

Parameters:

  • initial T

Returns:

  • *Signal[T]
Show/Hide Function Body
{
	s := &Signal[T]{value: initial, subs: make(map[*effect]struct{})}
	s.id = registerSignal(initial)
	return s
}

Effect function

Effect registers a reactive computation that automatically re-runs when its

dependent signals change. The provided function may return a cleanup function

that will run before the next execution and when the effect is stopped.

Parameters:

  • fn func() func()

Returns:

  • func()
Show/Hide Function Body
{
	e := &effect{run: fn}
	e.runEffect()
	return e.stop
}

TestUnregisterStore function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	sm := &StoreManager{modules: make(map[string]map[string]*Store)}
	s := NewStore("test", WithModule("mod"))
	sm.RegisterStore("mod", "test", s)
	if sm.GetStore("mod", "test") == nil {
		t.Fatalf("expected store to be registered")
	}
	sm.UnregisterStore("mod", "test")
	if sm.GetStore("mod", "test") != nil {
		t.Fatalf("expected store to be unregistered")
	}
}

testing import

Import example:

import "testing"

context import

Import example:

import "context"

strings import

Import example:

import "strings"

testing import

Import example:

import "testing"

testing import

Import example:

import "testing"

github.com/rfwlab/rfw/v1/js import

Import example:

import "github.com/rfwlab/rfw/v1/js"

Imported as:

js

fmt import

Import example:

import "fmt"

testing import

Import example:

import "testing"

testing import

Import example:

import "testing"

github.com/rfwlab/rfw/v1/js import

Import example:

import "github.com/rfwlab/rfw/v1/js"

Imported as:

js

encoding/json import

Import example:

import "encoding/json"

github.com/rfwlab/rfw/v1/js import

Import example:

import "github.com/rfwlab/rfw/v1/js"

Imported as:

js

sync import

Import example:

import "sync"

context import

Import example:

import "context"

testing import

Import example:

import "testing"

testing import

Import example:

import "testing"

log import

Import example:

import "log"

reflect import

Import example:

import "reflect"

strings import

Import example:

import "strings"

sync import

Import example:

import "sync"

reflect import

Import example:

import "reflect"

testing import

Import example:

import "testing"

testing import

Import example:

import "testing"