Agentic Coding

AI-Assisted React Development Guide

Learn how to build a React feature end-to-end with AI coding assistants — from component scaffolding to state management, typing, and testing in a real project.

May 31, 2026 10 min read
AI-Assisted React Development Guide

AI-assisted React development isn't about generating entire apps and hoping they work. It's about pairing an AI coding assistant with your own judgment to move through the parts of React work that are repetitive (boilerplate, typing, prop drilling, test setup) so you can spend your thinking on the architecture that actually matters. At Laxaar, we've shipped dozens of React projects and we've found that the engineers who get the most from AI tools are the ones who stay firmly in the driver's seat.

This tutorial walks you through building a filterable product listing page in React with TypeScript. We'll use Claude Code as the AI assistant, but the workflow applies equally to GitHub Copilot or Cursor. By the end you'll have a reusable pattern for AI-assisted component development that you can apply to any feature.

What you'll build

Step 1: Set up the project and brief the AI

Start with a fresh Vite + React + TypeScript project. We pick Vite over Create React App because it's actively maintained and the dev server is noticeably faster.

npm create vite@latest product-listing -- --template react-ts
cd product-listing
npm install
npm run dev

You should see the Vite default page at http://localhost:5173. Now install a few dependencies we'll need:

npm install @tanstack/react-query axios
npm install -D @testing-library/react @testing-library/user-event vitest jsdom

Before you type a single prompt, write a short brief in a BRIEF.md file at the project root. This is the step most developers skip, and it's the one that determines whether AI output is useful or garbage.

# Feature brief — Product listing page

Goal: filterable, paginated product list.
Data: REST API at /api/products returning { id, name, category, price, inStock }.
Filters: category (multi-select), price range (min/max), inStock toggle.
State: URL search params (so filters are shareable).
Stack: React 18, TypeScript 5, TanStack Query v5, no CSS framework.
Tests: Vitest + Testing Library.

Pass this brief to your AI assistant at the start of the session. A concrete brief gets concrete output. Vague prompts get vague code.

Step 2: Scaffold the component tree with AI assistance

Ask the AI to propose a component tree before writing any code. This is where AI assistance genuinely earns its keep — it can suggest a structure you'd arrive at anyway, but in seconds instead of minutes.

Prompt to use:

Given the brief in BRIEF.md, propose a component tree for the product listing feature.
Show the components, their props, and which ones own state.
Don't write the code yet — just the structure.

A sensible output looks like:

ProductListingPage       (owns URL param state, fetches data)
  FilterPanel            (receives filters + onChange callbacks)
    CategoryFilter       (multi-select checkboxes)
    PriceRangeFilter     (two number inputs)
    InStockToggle        (checkbox)
  ProductGrid            (receives products array)
    ProductCard          (receives single product)
  Pagination             (receives page + totalPages + onPageChange)

Review this before accepting it. Laxaar's engineers always ask: "Does any component own too much?" In this case ProductListingPage is fine as the single source of truth because the state is shallow. If filters were complex nested objects we'd split them out to a context or Zustand store.

Once you've approved the structure, ask the AI to scaffold the files:

# Ask the AI:
# "Create the files for each component with empty shells — correct props interfaces
#  and placeholder return values. Don't implement logic yet."

Expected output: five .tsx files under src/components/ with TypeScript interfaces and return null bodies. Verify the file structure before moving on — it's faster to fix a wrong tree now than after logic is woven through it.

Step 3: Wire up state management and filtering logic

URL search params are the right call for filter state on a listing page — they're shareable, bookmarkable, and survive a page refresh. The browser's built-in URLSearchParams API handles serialisation without adding a library.

Ask the AI to implement the state hook first, separate from the component:

Implement a custom hook useProductFilters() that reads and writes filters
to URL search params. Return { filters, setCategory, setPriceRange, setInStock, resetFilters }.
Use React Router v6's useSearchParams.

Install React Router if you haven't:

npm install react-router-dom

The hook the AI produces should look roughly like this — check it against this pattern:

// src/hooks/useProductFilters.ts
import { useSearchParams } from 'react-router-dom';

export interface ProductFilters {
  categories: string[];
  minPrice: number;
  maxPrice: number;
  inStock: boolean;
}

export function useProductFilters() {
  const [params, setParams] = useSearchParams();

  const filters: ProductFilters = {
    categories: params.getAll('category'),
    minPrice: Number(params.get('minPrice') ?? 0),
    maxPrice: Number(params.get('maxPrice') ?? 9999),
    inStock: params.get('inStock') === 'true',
  };

  function setCategory(categories: string[]) {
    setParams(prev => {
      prev.delete('category');
      categories.forEach(c => prev.append('category', c));
      return prev;
    });
  }

  function setPriceRange(min: number, max: number) {
    setParams(prev => {
      prev.set('minPrice', String(min));
      prev.set('maxPrice', String(max));
      return prev;
    });
  }

  function setInStock(value: boolean) {
    setParams(prev => { prev.set('inStock', String(value)); return prev; });
  }

  function resetFilters() { setParams({}); }

  return { filters, setCategory, setPriceRange, setInStock, resetFilters };
}

Read this code. Don't merge it blindly. Common AI mistakes here: forgetting prev.delete before appending multi-value params, or using navigate instead of setParams (which causes a full page transition). Both break the UX.

Now wire up TanStack Query in ProductListingPage:

// src/pages/ProductListingPage.tsx
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { useProductFilters } from '../hooks/useProductFilters';

export function ProductListingPage() {
  const { filters, ...filterSetters } = useProductFilters();

  const { data, isPending, isError } = useQuery({
    queryKey: ['products', filters],
    queryFn: () =>
      axios.get('/api/products', { params: filters }).then(r => r.data),
  });

  if (isPending) return <p>Loading products…</p>;
  if (isError) return <p>Something went wrong. Try refreshing.</p>;

  return (
    <div className="product-listing">
      <FilterPanel filters={filters} {...filterSetters} />
      <ProductGrid products={data.products} />
      <Pagination page={data.page} totalPages={data.totalPages} />
    </div>
  );
}

The query key includes the full filters object, so any filter change triggers a fresh fetch automatically. That's one of the things TanStack Query does well.

Step 4: Add TypeScript types and validate with the AI

Ask the AI to audit the types across all components and produce a single src/types/product.ts file:

Review all component files and extract a canonical types file at src/types/product.ts.
Include Product, ProductFilters, ApiResponse<T>, and PaginationMeta.
Make sure every component imports from this file instead of defining local interfaces.

Expected output:

// src/types/product.ts
export interface Product {
  id: string;
  name: string;
  category: string;
  price: number;
  inStock: boolean;
}

export interface PaginationMeta {
  page: number;
  totalPages: number;
  totalCount: number;
}

export interface ApiResponse<T> {
  data: T;
  pagination: PaginationMeta;
}

Run the TypeScript compiler to confirm there are no errors before writing tests:

npx tsc --noEmit

Zero errors is the only acceptable result. If the AI introduced any any types or mismatched interfaces, fix them now. We've found that accepting any at this stage multiplies into hours of debugging later — it's not a trade-off worth making.

Step 5: Generate and review component tests

Testing is where AI assistance saves the most time in React work. Writing test boilerplate is tedious; writing meaningful assertions isn't. Let the AI handle the boilerplate, then you write the assertions that matter.

Prompt:

Write Vitest + Testing Library tests for useProductFilters.
Cover: initial state reads from URL params, setCategory updates the URL,
resetFilters clears all params. Mock useSearchParams.

A sample test file:

// src/hooks/useProductFilters.test.ts
import { renderHook, act } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { useProductFilters } from './useProductFilters';

function wrapper({ children }: { children: React.ReactNode }) {
  return <MemoryRouter initialEntries={['/?category=shoes&inStock=true']}>{children}</MemoryRouter>;
}

test('reads initial filters from URL params', () => {
  const { result } = renderHook(() => useProductFilters(), { wrapper });
  expect(result.current.filters.categories).toEqual(['shoes']);
  expect(result.current.filters.inStock).toBe(true);
});

test('setCategory updates URL params', async () => {
  const { result } = renderHook(() => useProductFilters(), { wrapper });
  act(() => result.current.setCategory(['boots', 'sandals']));
  expect(result.current.filters.categories).toEqual(['boots', 'sandals']);
});

test('resetFilters clears all params', () => {
  const { result } = renderHook(() => useProductFilters(), { wrapper });
  act(() => result.current.resetFilters());
  expect(result.current.filters.categories).toEqual([]);
  expect(result.current.filters.inStock).toBe(false);
});

Run the suite:

npx vitest run

If tests fail, paste the error output back to the AI with the failing test and the current implementation side by side. Don't ask "why is this failing?" — ask "here's the error, here's the code, what's wrong?" Specific context gets specific fixes.

Common pitfalls

Accepting AI output without reading it. The AI doesn't know your API contract, your team's conventions, or your existing codebase. Treat every output as a first draft from a fast junior developer — review before merge.

Letting the AI choose the state management approach. If you don't specify, you might get useState scattered across five components, a Context API setup, Zustand, and Jotai in the same project. Set the pattern in your brief and enforce it.

Skipping the type audit step. AI-generated React code often introduces duplicate or incompatible interfaces. Running tsc --noEmit before writing tests catches these before they compound.

Using deprecated React APIs. Models trained before mid-2024 may still suggest componentDidMount, the old useEffect + useState data-fetching pattern instead of TanStack Query, or ReactDOM.render instead of createRoot. Verify the APIs are current.

Frequently Asked Questions

Which AI coding assistant works best for React development?

Claude Code, GitHub Copilot, and Cursor all produce solid React output. The difference is workflow: Claude Code handles multi-file refactors and long prompts well; Copilot's inline completions are faster for small edits; Cursor's codebase context is useful for large repos. The tool matters less than the quality of your prompts.

How do I stop the AI from generating components that are too large?

Be explicit in your prompt: "Each component should do one thing and have no more than 80 lines." AI assistants respect constraints when you state them. If a component grows beyond that, ask the AI to split it and tell it which pieces belong where.

Can the AI handle React Server Components?

Yes, but you need to specify the rendering model explicitly. State whether components run on the server or client, and whether you're using the App Router or Pages Router. Without that context the AI may mix paradigms incorrectly.

Is it safe to use AI-generated code in production?

It depends on your review process, not the AI. At Laxaar we treat AI output like any other code: it goes through the same PR review, the same type checks, and the same test suite. The source of the code doesn't change the review standard.

How do I keep the AI's output consistent with our codebase style?

Feed it examples. Paste 2-3 existing components from your project at the start of the session and ask the AI to match the style. That's more effective than describing the style in words.

What's the biggest mistake teams make with AI-assisted React work?

Generating too much at once. Asking for a complete feature in one prompt produces code you can't review effectively. Ask for one component at a time, review it, then move on. Smaller prompts, faster iteration.


If you're exploring AI-assisted development for a React project, the Laxaar team is building in this space and available to talk through your architecture. See our AI agent expertise or get in touch to discuss your project.

ReactAI CodingTypeScript
Grow your business with us

Take your business to the next level.

Tell us what you're building. We'll come back inside one business day with a fixed scope, timeline, and team — or an honest “this isn't a fit”.

ENGINEERING PHILOSOPHY

Code is useless if it's not comprehensible to those who maintain it. We write code the next person can actually understand.