# State Management

The modeler uses [Zustand](https://github.com/pmndrs/zustand) for state
management. For the complete reference, see `ui/docs/state-management.md`.

## Core principles

### Single source of truth

All application state lives in the Zustand store (`store/store.ts`). ReactFlow
is the sole authority for node and edge data -- the store holds the ReactFlow
instance's state.

### Individual selectors

Always use individual selectors, never destructure the store:

```typescript
// Correct
const nodes = useStore(state => state.nodes);
const selectedNode = useStore(state => state.selectedNode);

// Wrong -- causes unnecessary re-renders
const { nodes, selectedNode } = useStore();
```

### Effect dependencies

Never put `nodes` or `edges` arrays in `useEffect` dependency arrays -- they
change on every render. Use specific values instead:

```typescript
// Correct
const nodeCount = useStore(state => state.nodes.length);
useEffect(() => { /* ... */ }, [nodeCount]);

// Wrong -- fires on every render
const nodes = useStore(state => state.nodes);
useEffect(() => { /* ... */ }, [nodes]);
```

## Store structure

The store manages:

- **Model data**: Nodes, edges, metadata, and dirty state.
- **Selection**: Currently selected node(s) and edge(s).
- **UI state**: Dark mode, search, replay mode, panel visibility.
- **Modal state**: Which dialogs are open and their parameters.
- **Context state**: `contexts`, `selectedContextId`, `contextConfig`, and `dependencies` for component filtering.
- **Flow filtering**: `visibleStartNodeIds` for showing/hiding individual event flows.
- **Component labels**: `componentLabels` for model-owner-specific terminology.
- **Token state**: `isTokenDragging` to coordinate token drag feedback across panels.
- **Error log**: `errorLog` for tracking runtime errors.

## Modal state

Modals use the `useModalState` hook with a `showConfirmationDialog` method
that accepts an options bag for customizing button labels and variants:

```typescript
const { showConfirmationDialog } = useModalState();

showConfirmationDialog(
  'Confirm deletion',
  'Are you sure you want to delete all selected items?',
  onConfirm,
  onCancel,
  onSecondary,
  { primaryLabel: 'Delete', primaryVariant: 'danger', secondaryLabel: false }
);
```

See `ui/docs/state-management.md` for advanced patterns and common pitfalls.
