React Hooks
The Reeflow React SDK provides the useReeflowComponent hook to access component state, data, and control methods without managing refs or event listeners manually.
useReeflowComponent
Section titled “useReeflowComponent”The main hook that provides comprehensive access to a Reeflow component’s state, data, errors, and control methods.
Signature
Section titled “Signature”function useReeflowComponent(componentId: string): { state: 'initializing' | 'loading' | 'ready' | 'error' | 'empty' | undefined; data: QueryResult | undefined; error: ApiError | undefined; isLoading: boolean; isReady: boolean; isError: boolean; isEmpty: boolean; refresh: () => void; reset: (includeQuery?: boolean) => void;};Parameters
Section titled “Parameters”componentId- The unique ID of the Reeflow component (must match the component’sidprop)
Return value
Section titled “Return value”State & Data:
state- Current component state:'initializing','loading','ready','error', or'empty'data- Query result data when availableerror- Error object if an error occurred
Convenience Booleans:
isLoading-truewhen state is'loading'isReady-truewhen state is'ready'isError-truewhen state is'error'isEmpty-truewhen state is'empty'
Control Methods:
refresh()- Re-execute the current query to refresh datareset(includeQuery?)- Reset component to initial state (optionally reset query too)
Basic usage
Section titled “Basic usage”import { ReeflowBarChart, useReeflowComponent } from '@reeflow/react';
function SalesChart() { const { data, isLoading, isError, error } = useReeflowComponent('sales-chart');
return ( <div> {isLoading && <Spinner />} {isError && <ErrorMessage error={error} />} {data && <p>Loaded {data.row_count} rows</p>}
<ReeflowBarChart id="sales-chart" query={query} /> </div> );}Examples
Section titled “Examples”Loading and error states
Section titled “Loading and error states”Always provide user feedback for loading and error states:
import { ReeflowBarChart, useReeflowComponent } from '@reeflow/react';
function RevenueChart() { const { isLoading, isError, error, data } = useReeflowComponent('revenue-chart');
return ( <div> {isLoading && ( <div className="loading-banner"> <Spinner /> Loading chart data... </div> )}
{isError && ( <div className="error-banner"> <strong>Error:</strong> {error?.message} </div> )}
{data && ( <div className="stats-badge"> {data.row_count} rows • {data.execution_time_ms}ms </div> )}
<ReeflowBarChart id="revenue-chart" title="Monthly Revenue" query={{ type: 'aggregate', query: { measures: [{ column: 'revenue', type: 'sum' }], dimensions: [{ column: 'month', type: 'time', granularity: 'month' }], }, }} /> </div> );}Using refresh and reset
Section titled “Using refresh and reset”Control your component programmatically with refresh() and reset():
import { ReeflowBarChart, useReeflowComponent } from '@reeflow/react';
function InteractiveChart() { const { data, refresh, reset, isLoading } = useReeflowComponent('chart');
return ( <div> <div className="chart-controls"> <button onClick={refresh} disabled={isLoading}> <RefreshIcon /> Refresh Data </button> <button onClick={() => reset()} disabled={isLoading}> <ResetIcon /> Reset State </button> <button onClick={() => reset(true)} disabled={isLoading}> <ResetIcon /> Reset Query & State </button> </div>
{data && <p className="stats">Last updated: {new Date().toLocaleTimeString()}</p>}
<ReeflowBarChart id="chart" query={query} /> </div> );}Dashboard with multiple components
Section titled “Dashboard with multiple components”Coordinate state across multiple charts for a unified loading experience:
import { ReeflowBarChart, ReeflowLineChart, useReeflowComponent } from '@reeflow/react';
function Dashboard() { const revenue = useReeflowComponent('revenue-chart'); const orders = useReeflowComponent('orders-chart'); const customers = useReeflowComponent('customers-chart');
const isLoading = revenue.isLoading || orders.isLoading || customers.isLoading; const hasErrors = revenue.isError || orders.isError || customers.isError; const isReady = revenue.isReady && orders.isReady && customers.isReady;
const refreshAll = () => { revenue.refresh(); orders.refresh(); customers.refresh(); };
return ( <div className="dashboard"> <div className="dashboard-header"> <h1>Sales Dashboard</h1> <button onClick={refreshAll} disabled={isLoading}> Refresh All </button>
{isLoading && <span className="loading-badge">Loading...</span>} {hasErrors && <span className="error-badge">Some charts failed</span>} {isReady && <span className="success-badge">All data loaded</span>} </div>
<div className="charts-grid"> <div className="chart-card"> <ReeflowLineChart id="revenue-chart" title="Revenue Trend" query={revenueQuery} /> {revenue.data && <p className="chart-meta">{revenue.data.row_count} data points</p>} </div>
<div className="chart-card"> <ReeflowBarChart id="orders-chart" title="Orders by Category" query={ordersQuery} /> {orders.data && <p className="chart-meta">{orders.data.row_count} categories</p>} </div>
<div className="chart-card"> <ReeflowLineChart id="customers-chart" title="New Customers" query={customersQuery} /> {customers.data && <p className="chart-meta">{customers.data.row_count} months</p>} </div> </div> </div> );}Deriving data from query results
Section titled “Deriving data from query results”Use the hook to compute derived statistics from query results:
import { ReeflowBarChart, useReeflowComponent } from '@reeflow/react';
function SalesAnalysis() { const { data, isReady } = useReeflowComponent('sales-chart');
// Compute derived statistics const stats = data?.rows ? { total: data.rows.reduce((sum, row) => sum + (row.revenue || 0), 0), average: data.rows.reduce((sum, row) => sum + (row.revenue || 0), 0) / data.rows.length, max: Math.max(...data.rows.map((row) => row.revenue || 0)), min: Math.min(...data.rows.map((row) => row.revenue || 0)), } : null;
return ( <div> {isReady && stats && ( <div className="stats-panel"> <div className="stat"> <label>Total Revenue</label> <value>${stats.total.toLocaleString()}</value> </div> <div className="stat"> <label>Average</label> <value>${stats.average.toLocaleString()}</value> </div> <div className="stat"> <label>Highest</label> <value>${stats.max.toLocaleString()}</value> </div> <div className="stat"> <label>Lowest</label> <value>${stats.min.toLocaleString()}</value> </div> </div> )}
<ReeflowBarChart id="sales-chart" title="Revenue by Product" query={query} /> </div> );}Best practices
Section titled “Best practices”Use unique component IDs
Section titled “Use unique component IDs”Each Reeflow component instance must have a unique ID:
// ✅ Good - unique IDs<ReeflowBarChart id="revenue-chart" ... /><ReeflowBarChart id="orders-chart" ... />
// ❌ Bad - duplicate IDs<ReeflowBarChart id="chart" ... /><ReeflowBarChart id="chart" ... />Always handle loading and error states
Section titled “Always handle loading and error states”Provide feedback to improve user experience:
function MyChart() { const { isLoading, isError, error, data } = useReeflowComponent('my-chart');
return ( <div> {isLoading && <LoadingSpinner />} {isError && <ErrorBanner error={error} />} {data && <SuccessBadge count={data.row_count} />}
<ReeflowBarChart id="my-chart" ... /> </div> );}Inline queries are supported
Section titled “Inline queries are supported”You don’t need useMemo() for query objects. The SDK automatically performs deep equality checks:
// ✅ This works perfectly - no useMemo needed!<ReeflowBarChart id="chart" query={{ type: 'aggregate', query: { measures: [{ column: 'revenue', type: 'sum' }], }, }}/>;You can still use useMemo() if the query depends on props or state variables:
const query = useMemo( () => ({ type: 'aggregate', query: { measures: [{ column: selectedField, type: 'sum' }], }, }), [selectedField], // Re-create only when selectedField changes);TypeScript support
Section titled “TypeScript support”All hooks are fully typed. Import types from @reeflow/core:
import type { QueryResult, ApiError } from '@reeflow/core';import { useReeflowComponent } from '@reeflow/react';
function MyChart() { const { data, error }: { data: QueryResult | undefined; error: ApiError | undefined; } = useReeflowComponent('my-chart');
// TypeScript knows the exact types if (data) { console.log(data.row_count); // ✅ Type-safe console.log(data.execution_time_ms); // ✅ Type-safe }
if (error) { console.log(error.code); // ✅ Type-safe console.log(error.message); // ✅ Type-safe }
return <ReeflowBarChart id="my-chart" ... />;}Event handler props
Section titled “Event handler props”All Reeflow React components automatically include event handler props for both standard events and component-specific events:
Standard Events (available on all components):
<ReeflowBarChart id="chart" query={query} onStateChange={(event) => console.log('State changed:', event.detail)} onDataLoaded={(event) => console.log('Data loaded:', event.detail)} onError={(event) => console.error('Error:', event.detail)}/>;Component-Specific Events:
// Chart components<ReeflowBarChart id="chart" query={query} onChartClick={(event) => console.log('Chart clicked:', event.detail)}/>
// Table component<ReeflowTable id="table" query={query} onTableRowClick={(event) => console.log('Row clicked:', event.detail)} onTableSortChange={(event) => console.log('Sort changed:', event.detail)} onTablePageChange={(event) => console.log('Page changed:', event.detail)} onTableSearchChange={(event) => console.log('Search changed:', event.detail)}/>These event handlers are auto-generated from the Core SDK’s custom-elements.json manifest using @fires JSDoc annotations.
See Chart Components and Table Component for complete event details.
Related documentation
Section titled “Related documentation”- Getting Started - Set up the Reeflow SDK
- Chart Components - Available chart types and event handlers
- Table Component - Interactive data tables
- React API Reference - Full TypeScript API documentation