Skip to content

Store Class

Container class for grouping observables and managing reactive state.

FynX Store - Reactive State Management Components

This module provides the core components for reactive state management in FynX, enabling you to create organized, reactive state containers that group related observables together with convenient subscription and state management methods.

Why Use Stores?

Stores help you organize your application's reactive state into logical units. Instead of having observables scattered throughout your codebase, Stores group related data together and provide convenient methods for subscribing to changes, serializing state, and managing the reactive lifecycle.

Stores are particularly useful for: - Application State: Global app state like user preferences, theme settings - Feature State: State for specific features like shopping cart, user profile - Component State: Local state that needs to be shared across multiple components - Business Logic: Computed values and derived state based on raw data

Core Components

Store: A base class for creating reactive state containers. Store classes can define observable attributes using the observable() descriptor, and automatically provide methods for subscribing to changes and managing state.

observable: A descriptor function that creates observable attributes on Store classes. Use this to define reactive properties in your Store subclasses.

StoreSnapshot: An immutable snapshot of store state at a specific point in time, useful for debugging, logging, and ensuring consistent state access.

StoreMeta: A metaclass that automatically converts observable attributes to descriptors and provides type hint compatibility for mypy.

Key Features

  • Automatic Observable Management: Store metaclass handles observable creation
  • Convenient Subscriptions: Subscribe to all changes or individual observables
  • State Serialization: Save and restore store state with to_dict() and load_state()
  • Type Safety: Full type hint support for better IDE experience
  • Memory Efficient: Automatic cleanup and efficient change detection
  • Composable: Easy to combine and nest multiple stores

Basic Usage

from fynx import Store, observable

class CounterStore(Store):
    count = observable(0)
    name = observable("My Counter")

# Access values like regular attributes
print(CounterStore.count)  # 0
CounterStore.count = 5     # Updates the observable

# Subscribe to all changes in the store
@CounterStore.subscribe
def on_store_change(snapshot):
    print(f"Store changed: count={snapshot.count}, name={snapshot.name}")

CounterStore.count = 10  # Triggers: "Store changed: count=10, name=My Counter"

Advanced Patterns

Computed Properties in Stores

from fynx import Store, observable

class UserStore(Store):
    first_name = observable("John")
    last_name = observable("Doe")
    age = observable(30)

    # Computed properties using the >> operator
    full_name = (first_name + last_name) >> (
        lambda fname, lname: f"{fname} {lname}"
    )

    is_adult = age >> (lambda a: a >= 18)

print(UserStore.full_name)  # "John Doe"
UserStore.first_name = "Jane"
print(UserStore.full_name)  # "Jane Doe" (automatically updated)

State Persistence

# Save store state
state = CounterStore.to_dict()
# state = {"count": 10, "name": "My Counter"}

# Restore state later
CounterStore.load_state(state)
print(CounterStore.count)  # 10

Store Composition

class AppStore(Store):
    theme = observable("light")
    language = observable("en")

class UserStore(Store):
    name = observable("Alice")
    preferences = observable({})

# Use both stores independently
AppStore.theme = "dark"
UserStore.name = "Bob"

Common Patterns

Singleton Stores: Use class-level access for global state:

class GlobalStore(Store):
    is_loading = observable(False)
    current_user = observable(None)

# Access globally
GlobalStore.is_loading = True

```

See Also

  • fynx.observable: Core observable classes and operators
  • fynx.computed: Creating computed properties
  • fynx.reactive: Reactive decorators for side effects
  • fynx.watch: Conditional reactive functions

Store

Base class for reactive state containers with observable attributes.

Store provides a convenient way to group related observable values together and manage their lifecycle as a cohesive unit. Store subclasses can define observable attributes using the observable() descriptor, and Store provides methods for subscribing to changes, serializing state, and managing the reactive relationships.

Key Features: - Automatic observable attribute detection and management - Convenient subscription methods for reacting to state changes - Serialization/deserialization support for persistence - Snapshot functionality for debugging and state inspection

Example
from fynx import Store, observable

class CounterStore(Store):
    count = observable(0)
    name = observable("Counter")

# Subscribe to all changes
@CounterStore.subscribe
def on_change(snapshot):
    print(f"Counter: {snapshot.count}, Name: {snapshot.name}")

# Changes trigger reactions
CounterStore.count = 5  # Prints: Counter: 5, Name: Counter
CounterStore.name = "My Counter"  # Prints: Counter: 5, Name: My Counter
Note

Store uses a metaclass to intercept attribute assignment, allowing Store.attr = value syntax to work seamlessly with observables.

load_state

load_state(state_dict)

Load state from a dictionary into the store's observables.

subscribe

subscribe(func)

Subscribe a function to react to all observable changes in the store.

to_dict

to_dict()

Serialize all observable values to a dictionary.

unsubscribe

unsubscribe(func)

Unsubscribe a function from all observables.

StoreMeta

Metaclass for Store to automatically convert observable attributes to descriptors and adjust type hints for mypy compatibility.

__setattr__

__setattr__(name, value)

Intercept class attribute assignment for observables.

StoreSnapshot

StoreSnapshot(store_class, observable_attrs)

Immutable snapshot of store observable values at a specific point in time.

__getattr__

__getattr__(name)

Access snapshot values or fall back to class attributes.

observable

observable(initial_value=None)

Create an observable with an initial value, used as a descriptor in Store classes.