home / skills / markhamsquareventures / essentials / react

react skill

/skills/react

npx playbooks add skill markhamsquareventures/essentials --skill react

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.3 KB
---
name: react
description: How to work effectively with React, always use when developing frontend components
---

# 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.

<code-snippet name="Controller Passing Props" lang="php">
// In Laravel controller
public function edit(Project $project): Response
{
    return Inertia::render('projects/edit', [
        'project' => $project->load('client'),
        'clients' => Client::orderBy('name')->get(),
    ]);
}
</code-snippet>

<code-snippet name="Page Receiving Props" lang="tsx">
// In React page component
import { Project, Client } from '@/types';

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 */}
        </Form>
    );
}
</code-snippet>

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`

<code-snippet name="Typed Component Example" lang="tsx">
import { cn } from '@/lib/utils';

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)}>
            <h3 className="font-semibold">{title}</h3>
            {description && <p className="text-muted-foreground">{description}</p>}
            {children}
        </div>
    );
}
</code-snippet>

### React 19 + React Compiler

- The React Compiler automatically memoizes components and hooks
- Do NOT manually add `useMemo`, `useCallback`, or `React.memo` unless profiling shows a specific need
- Write straightforward code and let the compiler optimize

### State Management

- Use React's built-in `useState` and `useReducer` for 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)

<code-snippet name="Accessing Shared Data" lang="tsx">
import { usePage } from '@inertiajs/react';
import { SharedData } from '@/types';

export function UserGreeting() {
    const { auth } = usePage<SharedData>().props;

    return <span>Hello, {auth.user.name}</span>;
}
</code-snippet>

### 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

<code-snippet name="Conditional Rendering Patterns" lang="tsx">
// Early return for loading state
function DataDisplay({ data, isLoading }: Props) {
    if (isLoading) {
        return <Skeleton />;
    }

    return (
        <div>
            {data.items.length > 0 && <ItemList items={data.items} />}
            {data.error ? <ErrorMessage error={data.error} /> : <SuccessIndicator />}
        </div>
    );
}
</code-snippet>

### File Naming

- Components: PascalCase (`UserCard.tsx`)
- Hooks: camelCase with `use` prefix (`useClipboard.ts`)
- Utilities: camelCase (`formatDate.ts`)
- Pages: kebab-case matching the route (`edit.tsx`, `create.tsx`, `index.tsx`)