Hooks
Utility hooks for advanced spreadsheet functionality
The spreadsheet provides several utility hooks for common operations beyond the main useSpreadsheetState hook.
useNavigateToSheetRange
Navigate to a specific cell or range in a sheet, optionally with a visual flash effect.
Basic Usage
import { useNavigateToSheetRange } from "@rowsncolumns/spreadsheet";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";
function MySpreadsheet() {
const navigateToSheetRange = useNavigateToSheetRange();
const handleGoToRange = () => {
navigateToSheetRange?.({
sheetId: 2,
startRowIndex: 10,
endRowIndex: 15,
startColumnIndex: 5,
endColumnIndex: 8,
});
};
return (
<button onClick={handleGoToRange}>
Go to Sheet 2, Range F11:I16
</button>
);
}Parameters
navigateToSheetRange(
sheetRange: SheetRange, // The range to navigate to
enableFlash?: boolean, // Show flash effect (default: true)
flashColor?: Color, // Flash color (default: "#ffcc00")
flashDuration?: number // Flash duration in ms (default: 1500)
)Features
Sheet switching: Automatically switches to the target sheet
Cell positioning: Sets active cell to the top-left of the range
Scrolling: Scrolls the range into view
Visual feedback: Optional flash effect to highlight the range
Example with Custom Flash
const navigateToSheetRange = useNavigateToSheetRange();
// Navigate with red flash for 2 seconds
navigateToSheetRange?.(
{
sheetId: 1,
startRowIndex: 5,
endRowIndex: 10,
startColumnIndex: 3,
endColumnIndex: 6,
},
true, // Enable flash
"#ff0000", // Red color
2000 // 2 seconds
);Use Cases
Jump to errors: Navigate to cells with validation errors
Go to formulas: Jump to cells referenced in formulas
Search results: Navigate to search result cells
Links: Implement cell links to other sheet locations
Named ranges: Jump to named range locations
useLoadingIndicator
Display a loading indicator during async operations.
Basic Usage
import { useLoadingIndicator, LoadingIndicator } from "@rowsncolumns/spreadsheet";
function MySpreadsheet() {
const [showLoader, hideLoader] = useLoadingIndicator();
const handleAsyncOperation = async () => {
showLoader();
try {
await someAsyncOperation();
} finally {
hideLoader();
}
};
return (
<>
<button onClick={handleAsyncOperation}>
Load Data
</button>
<CanvasGrid />
<LoadingIndicator />
</>
);
}API
The hook returns a tuple:
const [showLoader, hideLoader] = useLoadingIndicator();showLoader(): Shows the loading indicatorhideLoader(): Hides the loading indicator
Example with Multiple Operations
function SpreadsheetWithAsyncOps() {
const [showLoader, hideLoader] = useLoadingIndicator();
const loadData = async () => {
showLoader();
try {
const data = await fetchSpreadsheetData();
setSheetData(data);
} catch (error) {
console.error("Failed to load data:", error);
} finally {
hideLoader();
}
};
const saveData = async () => {
showLoader();
try {
await saveSpreadsheetData(sheetData);
} finally {
hideLoader();
}
};
return (
<>
<button onClick={loadData}>Load</button>
<button onClick={saveData}>Save</button>
<CanvasGrid />
<LoadingIndicator />
</>
);
}Component
The LoadingIndicator component must be rendered in your app (typically at the root level):
<SpreadsheetProvider>
<Toolbar />
<CanvasGrid />
<LoadingIndicator /> {/* Required for the hook to work */}
</SpreadsheetProvider>Use Cases
Data loading: Show loader while fetching data from server
File import: Display during Excel/CSV import operations
Calculations: Show during long-running calculations
Export operations: Display while generating exports
useSpreadsheetApi
Access the imperative API for programmatic control of the spreadsheet.
Basic Usage
import { useSpreadsheetApi } from "@rowsncolumns/spreadsheet";
function MyComponent() {
const api = useSpreadsheetApi();
const updateCell = () => {
api?.getActiveSheet()
?.getRange({ rowIndex: 1, columnIndex: 1 })
.setValue("Hello World")
.setFormat("backgroundColor", "#ffcc00");
};
return <button onClick={updateCell}>Update A1</button>;
}See Imperative Spreadsheet API for complete documentation.
Complete Example
import React, { useState } from "react";
import {
SpreadsheetProvider,
CanvasGrid,
LoadingIndicator,
useLoadingIndicator,
useNavigateToSheetRange,
useSpreadsheetApi,
} from "@rowsncolumns/spreadsheet";
import {
useSpreadsheetState,
type SheetData,
} from "@rowsncolumns/spreadsheet-state";
function SpreadsheetWithHooks() {
const [sheets, setSheets] = useState([
{ sheetId: 1, rowCount: 100, columnCount: 26, title: "Sheet 1" },
{ sheetId: 2, rowCount: 100, columnCount: 26, title: "Sheet 2" },
]);
const [sheetData, setSheetData] = useState<SheetData>({});
return (
<SpreadsheetProvider>
<SpreadsheetControls
sheets={sheets}
sheetData={sheetData}
onChangeSheets={setSheets}
onChangeSheetData={setSheetData}
/>
</SpreadsheetProvider>
);
}
function SpreadsheetControls({ sheets, sheetData, onChangeSheets, onChangeSheetData }) {
const [showLoader, hideLoader] = useLoadingIndicator();
const navigateToSheetRange = useNavigateToSheetRange();
const api = useSpreadsheetApi();
const {
activeCell,
activeSheetId,
selections,
getCellData,
onChangeActiveCell,
onChangeSelections,
onChangeActiveSheet,
} = useSpreadsheetState({
sheets,
sheetData,
onChangeSheets,
onChangeSheetData,
});
const findAndNavigate = async () => {
showLoader();
try {
// Simulate search operation
await new Promise(resolve => setTimeout(resolve, 1000));
// Navigate to found cell
navigateToSheetRange?.({
sheetId: 2,
startRowIndex: 15,
endRowIndex: 15,
startColumnIndex: 5,
endColumnIndex: 5,
});
} finally {
hideLoader();
}
};
const updateCellProgrammatically = () => {
api?.getActiveSheet()
?.getRange({ rowIndex: 1, columnIndex: 1 })
.setValue("Updated via API");
};
return (
<>
<div className="toolbar">
<button onClick={findAndNavigate}>
Find and Navigate
</button>
<button onClick={updateCellProgrammatically}>
Update A1
</button>
</div>
<CanvasGrid
sheetId={activeSheetId}
activeCell={activeCell}
selections={selections}
getCellData={getCellData}
onChangeActiveCell={onChangeActiveCell}
onChangeSelections={onChangeSelections}
onChangeActiveSheet={onChangeActiveSheet}
/>
<LoadingIndicator />
</>
);
}
export default SpreadsheetWithHooks;Hook Dependencies
useNavigateToSheetRange
Requires SpreadsheetProvider context:
<SpreadsheetProvider>
{/* Component using useNavigateToSheetRange */}
</SpreadsheetProvider>useLoadingIndicator
Requires LoadingIndicator component to be rendered:
<SpreadsheetProvider>
<YourComponents />
<LoadingIndicator /> {/* Required */}
</SpreadsheetProvider>useSpreadsheetApi
Requires SpreadsheetProvider and active spreadsheet state:
<SpreadsheetProvider>
{/* Component using useSpreadsheetApi */}
</SpreadsheetProvider>Best Practices
useNavigateToSheetRange
User feedback: Always provide visual feedback when navigating (use flash effect)
Bounds checking: Ensure the range exists before navigating
Sheet existence: Verify the target sheet exists
useLoadingIndicator
Always hide: Use try-finally to ensure hideLoader is called
Error handling: Show errors to users if operations fail
Timeout: Consider adding timeouts for long operations
Multiple operations: Use separate show/hide pairs for different operations
useSpreadsheetApi
Null checking: Always use optional chaining (
api?.)State management: Prefer declarative state over imperative API when possible
Batch operations: Use batch methods for multiple changes
TypeScript Support
All hooks are fully typed:
import type { SheetRange, Color } from "@rowsncolumns/spreadsheet";
const navigateToSheetRange = useNavigateToSheetRange();
// Type: (range: SheetRange, flash?: boolean, color?: Color, duration?: number) => void
const [showLoader, hideLoader] = useLoadingIndicator();
// Type: [() => void, () => void]
const api = useSpreadsheetApi();
// Type: SpreadsheetAPI | nullTroubleshooting
useNavigateToSheetRange not working
Ensure you're inside SpreadsheetProvider:
<SpreadsheetProvider>
<YourComponent /> {/* Hook works here */}
</SpreadsheetProvider>LoadingIndicator not showing
Verify the component is rendered:
<LoadingIndicator /> {/* Must be present */}useSpreadsheetApi returns null
The API is only available after the spreadsheet is mounted:
useEffect(() => {
if (api) {
// API is ready
}
}, [api]);Last updated
Was this helpful?