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

data-hydration.mddocs/

Data Hydration

The data hydration system provides sophisticated serialization and deserialization capabilities for complex JavaScript objects, React elements, functions, and circular references to enable safe transport across DevTools communication boundaries.

Capabilities

Meta Symbols

Special symbols used to mark dehydrated data with metadata for proper reconstruction.

/**
 * Metadata symbols for dehydrated data identification
 */
const meta = {
  /** Symbol for marking dehydrated object names */
  name: Symbol('name');
  /** Symbol for marking dehydrated object types */
  type: Symbol('type');
  /** Symbol for marking inspection status */
  inspected: Symbol('inspected');
  /** Symbol for additional metadata */
  meta: Symbol('meta');
  /** Symbol for prototype information */
  proto: Symbol('proto');
};

Data Dehydration

Strips complex data types and deep nesting to create serializable representations for bridge transport.

/**
 * Strip complex data for safe serialization and bridge transport
 * Handles functions, React elements, circular references, and deep nesting
 * @param data - Object to dehydrate
 * @param cleaned - Array to track cleaned paths
 * @param path - Current object path (internal)
 * @param level - Current nesting level (internal)
 * @returns Serializable representation of the data
 */
function dehydrate(
  data: Object,
  cleaned: Array<Array<string>>,
  path?: Array<string>,
  level?: number
): string | Object;

Usage Examples:

import { dehydrate } from "react-devtools-experimental/src/hydration";

// Complex object with functions and React elements
const complexData = {
  user: {
    name: 'John',
    onClick: () => console.log('clicked'),
    component: <MyComponent prop="value" />
  },
  settings: {
    theme: 'dark',
    nested: {
      deep: {
        value: 'test'
      }
    }
  }
};

const cleaned = [];
const dehydrated = dehydrate(complexData, cleaned);

console.log(dehydrated);
// {
//   user: {
//     name: 'John',
//     onClick: { name: 'onClick', type: 'function' },
//     component: { name: 'MyComponent', type: 'react_element' }
//   },
//   settings: {
//     theme: 'dark',
//     nested: { type: 'object', name: '', meta: {} }
//   }
// }

console.log(cleaned);
// [['user', 'onClick'], ['user', 'component'], ['settings', 'nested']]

Data Hydration

Restores dehydrated data by adding metadata symbols to enable DevTools inspection.

/**
 * Restore dehydrated data with metadata symbols
 * Converts cleaned representations back to inspectable objects
 * @param data - Dehydrated data object
 * @param cleaned - Array of cleaned paths to restore
 * @returns Data with metadata symbols for DevTools inspection
 */
function hydrate(data: Object, cleaned: Array<Array<string>>): Object;

Usage Examples:

import { hydrate, meta } from "react-devtools-experimental/src/hydration";

// Hydrate previously dehydrated data
const hydrated = hydrate(dehydrated, cleaned);

// Check if a value is a dehydrated function
const onClick = hydrated.user.onClick;
if (onClick[meta.type] === 'function') {
  console.log(`Function name: ${onClick[meta.name]}`);
  console.log(`Inspected: ${onClick[meta.inspected]}`);
}

// Check if a value is a dehydrated React element
const component = hydrated.user.component;
if (component[meta.type] === 'react_element') {
  console.log(`Component name: ${component[meta.name]}`);
}

React Element Display Names

Specialized function for extracting display names from React elements.

/**
 * Get display name for React elements
 * Handles all React element types including built-ins and custom components
 * @param element - React element to get display name for
 * @returns Human-readable display name or null
 */
function getDisplayNameForReactElement(element: React$Element<any>): string | null;

Usage Examples:

import React from 'react';
import { getDisplayNameForReactElement } from "react-devtools-experimental/src/hydration";

// Built-in React elements
const fragment = <React.Fragment><div /></React.Fragment>;
console.log(getDisplayNameForReactElement(fragment)); // 'Fragment'

const suspense = <React.Suspense fallback="loading"><div /></React.Suspense>;
console.log(getDisplayNameForReactElement(suspense)); // 'Suspense'

// Custom components
function MyComponent() { return <div />; }
const customElement = <MyComponent />;
console.log(getDisplayNameForReactElement(customElement)); // 'MyComponent'

// Context components
const ThemeContext = React.createContext();
const provider = <ThemeContext.Provider value="dark"><div /></ThemeContext.Provider>;
console.log(getDisplayNameForReactElement(provider)); // 'ContextProvider'

Dehydration Process

Supported Data Types

The dehydration system handles various JavaScript data types with specific processing:

// String handling - truncated if too long
'function' -> { name: 'funcName', type: 'function' }
'symbol' -> { name: 'Symbol(description)', type: 'symbol' }
'react_element' -> { name: 'ComponentName', type: 'react_element' }
'array_buffer' -> { name: 'ArrayBuffer', type: 'array_buffer', meta: { length: 1024, uninspectable: true } }
'data_view' -> { name: 'DataView', type: 'data_view', meta: { length: 1024, uninspectable: true } }
'date' -> { name: 'Wed Oct 05 2023 14:48:00 GMT+0000 (UTC)', type: 'date', meta: { uninspectable: true } }
'array' -> [...] // Recursively processed
'typed_array' -> { type: 'typed_array', name: 'Uint8Array', meta: { length: 100, readOnly: true } }
'iterator' -> { type: 'iterator', name: 'MapIterator', meta: { readOnly: true } }
'object' -> {...} // Recursively processed or dehydrated if too deep/complex

Nesting Level Control

/**
 * Maximum nesting level before dehydration
 * Objects deeper than this level are automatically dehydrated
 */
const LEVEL_THRESHOLD = 6;

Usage Examples:

// Deep nesting automatically dehydrated
const deepObject = {
  level1: {
    level2: {
      level3: {
        level4: {
          level5: {
            level6: {
              level7: 'too deep' // This will be dehydrated
            }
          }
        }
      }
    }
  }
};

const cleaned = [];
const result = dehydrate(deepObject, cleaned);
// level7 object will be dehydrated due to depth

Custom Object Handling

/**
 * Create dehydrated representation for complex objects
 * @param type - Object type identifier  
 * @param data - Original object data
 * @param cleaned - Array to track cleaned paths
 * @param path - Object path location
 * @returns Dehydrated object representation
 */
function createDehydrated(
  type: string,
  data: Object,
  cleaned: Array<Array<string>>,
  path: Array<string>
): Object;

Advanced Usage Patterns

Custom Type Detection

The system includes intelligent type detection for complex objects:

// Type detection logic
function getPropType(data) {
  if (isElement(data)) return 'react_element';
  if (Array.isArray(data)) return 'array';
  if (ArrayBuffer.isView(data)) {
    if (data instanceof DataView) return 'data_view';
    return 'typed_array';
  }
  if (data instanceof ArrayBuffer) return 'array_buffer';
  if (typeof data[Symbol.iterator] === 'function') return 'iterator';
  if (Object.prototype.toString.call(data) === '[object Date]') return 'date';
  return typeof data;
}

Bridge Integration

The hydration system integrates seamlessly with bridge communication:

// Sending data across bridge
const originalData = { 
  components: [<MyComponent />, <AnotherComponent />],
  handlers: { onClick: () => {}, onSubmit: () => {} }
};

// Dehydrate for transport
const cleaned = [];
const dehydrated = dehydrate(originalData, cleaned);

// Send via bridge
bridge.send('component-data', { 
  data: dehydrated, 
  cleaned: cleaned 
});

// Receiving side
bridge.on('component-data', ({ data, cleaned }) => {
  const hydrated = hydrate(data, cleaned);
  
  // Now can inspect dehydrated values
  hydrated.components.forEach(component => {
    if (component[meta.type] === 'react_element') {
      console.log(`Component: ${component[meta.name]}`);
    }
  });
});

Error Handling

The hydration system includes robust error handling:

// Safe dehydration with error handling
function safeDehydrate(data) {
  try {
    const cleaned = [];
    return {
      data: dehydrate(data, cleaned),
      cleaned: cleaned,
      success: true
    };
  } catch (error) {
    console.error('Dehydration failed:', error);
    return {
      data: { error: 'Dehydration failed', message: error.message },
      cleaned: [],
      success: false
    };
  }
}

// Safe hydration with error handling  
function safeHydrate(data, cleaned) {
  try {
    return {
      data: hydrate(data, cleaned),
      success: true
    };
  } catch (error) {
    console.error('Hydration failed:', error);
    return {
      data: data, // Return original data
      success: false
    };
  }
}

Performance Optimization

Strategies for optimizing hydration performance:

// Cache display names to avoid repeated computation
const displayNameCache = new WeakMap();

function getCachedDisplayName(element) {
  if (displayNameCache.has(element)) {
    return displayNameCache.get(element);
  }
  
  const displayName = getDisplayNameForReactElement(element);
  displayNameCache.set(element, displayName);
  return displayName;
}

// Limit string length to prevent memory issues
function truncateString(str, maxLength = 500) {
  return str.length <= maxLength ? str : str.slice(0, maxLength) + '...';
}

// Batch dehydration operations
function batchDehydrate(objects) {
  const results = [];
  const globalCleaned = [];
  
  objects.forEach((obj, index) => {
    const cleaned = [];
    const dehydrated = dehydrate(obj, cleaned, [`batch_${index}`]);
    results.push(dehydrated);
    globalCleaned.push(...cleaned);
  });
  
  return { results, cleaned: globalCleaned };
}