React Development
Role in This Project
React is used only for interactive islands — calculator forms, dynamic UI, and anything that needs client-side state. All static content is rendered by Astro.
Component Pattern
interface TileCalculatorProps {
baseUrl?: string;
}
export default function TileCalculator({ baseUrl = '' }: TileCalculatorProps) {
// component logic
return (/* JSX */);
}
Do NOT use FC type. Use regular function declarations with typed props.
Rules
- Functional components only. No class components.
- Export as default from calculator component files (required for Astro island imports).
- No business logic in components. Import calculator functions from
src/calculators/. Components handle state and UI only. - Use controlled form inputs with
useStatefor calculator forms.
State Management
- Local state:
useStatefor component-scoped state (form inputs, results). - Cross-island state: Use Nanostores if multiple islands need shared state. Nanostores works with both Astro and React.
- Do NOT use Zustand, Redux, or Context — Nanostores is the standard for Astro multi-framework islands.
Calculator Component Structure
import { useState } from 'react';
import { calculateTiles } from '../../calculators/tiles';
import type { TileInput, TileResult } from '../../calculators/tiles';
export default function TileCalculator() {
const [input, setInput] = useState<TileInput>(defaultInput);
const [result, setResult] = useState<TileResult | null>(null);
const handleCalculate = () => {
setResult(calculateTiles(input));
};
return (
<div>
{/* Input form */}
{/* Calculate button */}
{/* Results display (conditional on result !== null) */}
</div>
);
}
Performance
- Use
useMemofor expensive derived calculations. - Use
useCallbackonly when passing callbacks to memoised children. - Do NOT premature-optimise — profile first.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.