or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

backend-agent.mdbridge-communication.mddata-hydration.mddevtools-ui.mdfrontend-store.mdhook-system.mdindex.mdperformance-profiling.md
tile.json

frontend-store.mddocs/

Frontend Store

The Frontend Store is the central state management system for the DevTools UI that maintains the element tree, handles bridge communication, manages profiling data, and provides event-driven updates to React components.

Capabilities

Store Class

Central state management class that extends EventEmitter for the DevTools frontend.

/**
 * Central state management for DevTools frontend
 * Manages element tree, profiling data, and bridge communication
 */
class Store extends EventEmitter {
  /**
   * Create a new store instance
   * @param bridge - Bridge for backend communication
   * @param config - Optional configuration settings
   */
  constructor(bridge: Bridge, config?: Config);
  
  /** Current profiling cache instance */
  get profilingCache(): ProfilingCache;
  
  /** Number of elements in the tree */
  get numElements(): number;
  
  /** Current tree revision number */
  get revision(): number;
  
  /** Array of root element IDs */
  get roots(): $ReadOnlyArray<number>;
  
  /** Whether profiling is supported */  
  get supportsProfiling(): boolean;
  
  /** Whether reload and profile is supported */
  get supportsReloadAndProfile(): boolean;
  
  /** Whether profiling is currently active */
  get isProfiling(): boolean;
  
  /** Whether profiling data is available */
  get hasProfilingData(): boolean;
}

interface Config {
  /** Enable reload and profile functionality */
  supportsReloadAndProfile?: boolean;
  /** Enable profiling functionality */
  supportsProfiling?: boolean;
}

Usage Examples:

import Store from "react-devtools-experimental/src/devtools/store";
import Bridge from "react-devtools-experimental/src/bridge";

// Create store with profiling support
const config = {
  supportsProfiling: true,
  supportsReloadAndProfile: true
};

const store = new Store(bridge, config);

// Listen for store updates
store.on('tree-updated', () => {
  console.log(`Tree updated, ${store.numElements} elements`);
});

// Check profiling status
if (store.supportsProfiling) {
  console.log(`Profiling active: ${store.isProfiling}`);
  console.log(`Has profiling data: ${store.hasProfilingData}`);
}

Element Access Methods

Methods for accessing and querying elements in the DevTools tree.

/**
 * Get element at specific index in the flattened tree
 * @param index - Zero-based index in the tree
 * @returns Element data or null if not found
 */
getElementAtIndex(index: number): Element | null;

/**
 * Get element ID at specific index
 * @param index - Zero-based index in the tree
 * @returns Element ID or null if not found
 */
getElementIDAtIndex(index: number): number | null;

/**
 * Get element by its unique ID
 * @param id - Element ID to look up
 * @returns Element data or null if not found
 */
getElementByID(id: number): Element | null;

/**
 * Get index of element with specific ID
 * @param id - Element ID to find index for
 * @returns Index in tree or null if not found
 */
getIndexOfElementID(id: number): number | null;

Usage Examples:

// Access elements by index
const firstElement = store.getElementAtIndex(0);
console.log('First element:', firstElement);

// Find element by ID
const elementID = 42;
const element = store.getElementByID(elementID);
if (element) {
  console.log(`Element ${elementID}:`, element.displayName);
}

// Get element index for scrolling
const elementIndex = store.getIndexOfElementID(elementID);
if (elementIndex !== null) {
  scrollToIndex(elementIndex);
}

// Iterate through all elements
for (let i = 0; i < store.numElements; i++) {
  const element = store.getElementAtIndex(i);
  if (element) {
    console.log(`${element.displayName} (depth: ${element.depth})`);
  }
}

Renderer Information

Methods for getting information about renderers and roots.

/**
 * Get renderer ID for a specific element
 * @param id - Element ID
 * @returns Renderer ID or null if not found
 */
getRendererIDForElement(id: number): number | null;

/**
 * Get root ID for a specific element
 * @param id - Element ID  
 * @returns Root ID or null if not found
 */
getRootIDForElement(id: number): number | null;

Usage Examples:

// Get renderer information for element
const elementID = 42;
const rendererID = store.getRendererIDForElement(elementID);
const rootID = store.getRootIDForElement(elementID);

console.log(`Element ${elementID}:`);
console.log(`  Renderer: ${rendererID}`);
console.log(`  Root: ${rootID}`);

// Use for backend operations
if (rendererID && rootID) {
  bridge.send('inspect-element', { 
    id: elementID, 
    rendererID: rendererID 
  });
}

Profiling Control

Methods for controlling performance profiling sessions.

/**
 * Start performance profiling session
 * Sends command to backend to begin collecting performance data
 */
startProfiling(): void;

/**
 * Stop performance profiling session
 * Sends command to backend to end data collection
 */
stopProfiling(): void;

Usage Examples:

// Start profiling session
if (store.supportsProfiling && !store.isProfiling) {
  store.startProfiling();
  console.log('Profiling started');
}

// Stop profiling session
if (store.isProfiling) {
  store.stopProfiling();
  console.log('Profiling stopped');
}

// Listen for profiling status changes
store.on('profiling-status-changed', (isProfiling) => {
  console.log(`Profiling ${isProfiling ? 'started' : 'stopped'}`);
  updateProfilingUI(isProfiling);
});

Event Handling

Key events emitted by the store for UI updates and data synchronization.

// Core store events
'tree-updated'              // Element tree has changed
'element-selected'          // Element selection changed
'profiling-status-changed'  // Profiling status changed
'profiling-data-available'  // New profiling data received
'bridge-connected'          // Backend bridge connected
'bridge-disconnected'       // Backend bridge disconnected
'store-reset'              // Store state reset

Usage Examples:

// Listen for tree updates
store.on('tree-updated', () => {
  // Re-render tree UI
  updateElementTree();
});

// Listen for element selection
store.on('element-selected', (elementID) => {
  // Update selection UI
  highlightSelectedElement(elementID);
  
  // Load element details
  loadElementInspection(elementID);
});

// Listen for profiling data
store.on('profiling-data-available', () => {
  // Update profiler UI
  if (store.hasProfilingData) {
    showProfilingResults();
  }
});

// Handle bridge disconnection
store.on('bridge-disconnected', () => {
  showDisconnectedState();
});

Bridge Operations Handling

Internal methods for processing bridge messages and operations.

/**
 * Handle operations from bridge
 * Internal method that processes tree operations from backend
 * @param operations - Serialized operations data
 */
onBridgeOperations(operations: Uint32Array): void;

/**
 * Handle profiling status updates
 * @param isProfiling - Current profiling status
 */
onProfilingStatus(isProfiling: boolean): void;

/**
 * Handle bridge shutdown
 * Cleans up resources when backend disconnects
 */
onBridgeShutdown(): void;

Debug Methods

Utility methods for debugging and development.

/**
 * Print element tree to console for debugging
 * Development/debug method to visualize tree structure
 */
__printTree(): void;

Usage Examples:

// Debug tree structure
if (process.env.NODE_ENV === 'development') {
  store.__printTree();
}

Element Data Structure

Element Interface

The primary data structure representing React elements in the DevTools tree.

interface Element {
  /** Unique element identifier */
  id: number;
  /** Parent element ID (0 for roots) */
  parentID: number;
  /** Array of child element IDs */
  children: Array<number>;
  /** Element type classification */
  type: ElementType;
  /** Display name for the element */
  displayName: string | null;
  /** React key prop */
  key: number | string | null;
  /** Owner element ID */
  ownerID: number;
  /** Nesting depth in tree */
  depth: number;
  /** Number of descendants */
  weight: number;
}

/** Element type constants */
const ElementTypeClass = 1;
const ElementTypeFunction = 2;
const ElementTypeContext = 3;
const ElementTypeForwardRef = 4;
const ElementTypeMemo = 5;
const ElementTypeOtherOrUnknown = 6;
const ElementTypeProfiler = 7;
const ElementTypeRoot = 8;
const ElementTypeSuspense = 9;

type ElementType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

Usage Examples:

// Process element based on type
const element = store.getElementByID(42);
if (element) {
  switch (element.type) {
    case ElementTypeClass:
      console.log(`Class component: ${element.displayName}`);
      break;
    case ElementTypeFunction:
      console.log(`Function component: ${element.displayName}`);
      break;
    case ElementTypeContext:
      console.log(`Context: ${element.displayName}`);
      break;
    default:
      console.log(`Other element: ${element.displayName}`);
  }
  
  // Access element hierarchy
  console.log(`Parent: ${element.parentID}`);
  console.log(`Children: ${element.children.length}`);
  console.log(`Depth: ${element.depth}`);
}

Store Integration Patterns

React Component Integration

Using the store with React components and hooks:

import { useContext, useEffect, useState } from 'react';
import { StoreContext } from 'react-devtools-experimental/src/devtools/views/context';

function ElementTree() {
  const store = useContext(StoreContext);
  const [revision, setRevision] = useState(store.revision);
  
  useEffect(() => {
    const handleTreeUpdate = () => {
      setRevision(store.revision);
    };
    
    store.on('tree-updated', handleTreeUpdate);
    return () => store.off('tree-updated', handleTreeUpdate);
  }, [store]);
  
  // Render tree based on current revision
  return (
    <div>
      {store.roots.map(rootID => (
        <ElementNode key={rootID} elementID={rootID} store={store} />
      ))}
    </div>
  );
}

Suspense Integration with Profiling Cache

The store integrates with React Suspense for async profiling data:

import { Suspense } from 'react';

function ProfilingResults() {
  const store = useContext(StoreContext);
  
  if (!store.hasProfilingData) {
    return <div>No profiling data available</div>;
  }
  
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ProfilingDataDisplay cache={store.profilingCache} />
    </Suspense>
  );
}

function ProfilingDataDisplay({ cache }) {
  // This will suspend if data is not ready
  const profilingData = cache.read();
  
  return (
    <div>
      <h3>Profiling Results</h3>
      <ProfilingChart data={profilingData} />
    </div>
  );
}

Store Lifecycle Management

Proper setup and cleanup of the store:

function createDevToolsStore(bridge, config) {
  const store = new Store(bridge, config);
  
  // Set up error handling
  store.on('error', (error) => {
    console.error('Store error:', error);
  });
  
  // Set up cleanup
  const cleanup = () => {
    store.removeAllListeners();
    store.onBridgeShutdown();
  };
  
  // Cleanup on page unload
  window.addEventListener('beforeunload', cleanup);
  
  return { store, cleanup };
}

// Usage
const { store, cleanup } = createDevToolsStore(bridge, config);

// Later cleanup
cleanup();