react
React
Instructions
This project uses React 19 with TypeScript and the React Compiler enabled via babel-plugin-react-compiler.
Component Structure
- Pages live in
resources/js/pages/and are rendered via Inertia - Shared components live in
resources/js/components/ - UI primitives (shadcn/ui) live in
resources/js/components/ui/ - Custom hooks live in
resources/js/hooks/
Page Props from Controllers
Always receive page data as props from the Laravel controller via Inertia. Do NOT fetch data client-side or use useEffect to load page data.
interface EditProjectProps { project: Project; clients: Client[]; }
export default function EditProject({ project, clients }: EditProjectProps) { return ( <Form action={update({ project: project.id }).url} method="patch"> {/* Form fields using project and clients data */} ); }
This pattern ensures:
- State consistency - The server is the single source of truth; no client-side caching or stale data issues
- Data is loaded server-side before the page renders
- No loading states needed for initial page data
- SEO-friendly server-rendered content
- Type-safe props matching controller output
TypeScript Conventions
- All component props should be typed explicitly
- Use interfaces for object shapes, defined in
resources/js/types/index.d.ts - Prefer
React.ComponentProps<"element">for extending native element props - Use path aliases:
@/components,@/hooks,@/lib,@/types
interface CardProps { title: string; description?: string; className?: string; children: React.ReactNode; }
export function Card({ title, description, className, children }: CardProps) { return ( <div className={cn('rounded-lg border p-4', className)}> {title} {description && {description}} {children} ); }
React 19 + React Compiler
- The React Compiler automatically memoizes components and hooks
- Do NOT manually add
useMemo,useCallback, orReact.memounless profiling shows a specific need - Write straightforward code and let the compiler optimize
State Management
- Use React's built-in
useStateanduseReducerfor local state - Use Inertia's shared data for server-provided state (accessed via
usePage()) - For form state, use the Inertia
<Form>component (see inertia skill)
export function UserGreeting() { const { auth } = usePage().props;
return <span>Hello, {auth.user.name}</span>;
}
Event Handlers
- Use inline arrow functions for simple handlers
- Extract to named functions only when logic is complex or reused
Conditional Rendering
- Use early returns for guard clauses
- Prefer
&&for simple conditionals, ternaries for if/else - Use separate components for complex conditional logic
return (
<div>
{data.items.length > 0 && <ItemList items={data.items} />}
{data.error ? <ErrorMessage error={data.error} /> : <SuccessIndicator />}
</div>
);
}
File Naming
- Components: PascalCase (
UserCard.tsx) - Hooks: camelCase with
useprefix (useClipboard.ts) - Utilities: camelCase (
formatDate.ts) - Pages: kebab-case matching the route (
edit.tsx,create.tsx,index.tsx)
More from markhamsquareventures/essentials
tailwind
How to work effectively with Tailwind CSS, always use when styling frontend features
35wayfinder
How to work effectively with Laravel Wayfinder, always use when developing frontend features
30shadcn
How to work effectively with shadcn/ui components, always use when adding UI components
26inertia
How to work effectively with Inertia, always use when developing frontend features
21pest
Pest framework syntax reference
20laravel
How to work effectively with Laravel, always use when developing Laravel features
16