DEV Community

Cover image for I Gave Cursor My React Codebase, Here Are 7 Things It Improved Instantly
Nabeel Krissane
Nabeel Krissane

Posted on

I Gave Cursor My React Codebase, Here Are 7 Things It Improved Instantly

You inherit a React codebase. Or worse you wrote it six months ago.

Either way, you open the project and see the same story: prop drilling three levels deep, useEffect hooks with missing dependencies, components that re-render for no reason, and API calls scattered across the app with no error handling.

This isn't a "bad developer" problem. It's a React codebase maintenance problem, and almost every team hits it as the app grows.

Manually auditing a large codebase for performance issues, bad patterns, and hidden bugs takes days. So I tried something different: I pointed Cursor AI, an AI-powered code editor built on top of VS Code, at a real React project and asked it to review the code.

In this article, you'll learn:

  • The 7 real issues Cursor AI found and fixed in a React codebase
  • The actual before/after code for each fix
  • Why these problems happen in the first place
  • Common mistakes React developers make with AI-assisted refactoring
  • Best practices to keep your codebase clean going forward

If you're a React developer looking to improve code quality with AI tools, this is a practical, no-fluff walkthrough — not a marketing pitch for Cursor.


Why React Codebases Get Messy (The Real Reason)

Before jumping into fixes, it's worth understanding why this happens.

React gives you flexibility, not structure. There's no built-in rule for where state should live, how components should be split, or how side effects should be managed.

So under deadline pressure, developers usually:

  • Copy-paste components instead of abstracting shared logic
  • Add useEffect without thinking about dependency arrays
  • Pass props through multiple layers instead of using context or state managers
  • Skip memoization because "it works fine locally"
  • Forget cleanup functions in effects that involve subscriptions or timers

None of these are catastrophic on their own. But they compound. After a few months, the codebase becomes fragile, slow, and hard to onboard new developers onto.

This is exactly the kind of pattern-recognition problem AI code review tools are good at — they don't get tired, and they scan the entire file tree consistently.


Solution Overview: Using Cursor AI as a Code Reviewer

Cursor AI lets you chat with your codebase, ask it to review specific files, and generate fixes directly in context — it understands imports, component relationships, and project structure, not just isolated snippets.

The workflow is simple:

  1. Open the codebase in Cursor
  2. Select a file or folder
  3. Ask Cursor to review it for bugs, performance issues, or anti-patterns
  4. Review the suggested diff
  5. Accept, reject, or modify the change

It's not magic — it's pattern matching at scale, backed by a large language model that has seen millions of React codebases. Let's go through what it actually caught.


Step-by-Step: How I Reviewed My React Codebase with Cursor

Step 1: Setup

Install Cursor from cursor.sh and open your existing React project folder directly — no migration needed since it's a VS Code fork.

# Cursor uses your existing project as-is
cd my-react-app
cursor .
Enter fullscreen mode Exit fullscreen mode

Step 2: Configuration

Enable "Codebase Indexing" in Cursor settings so it can reason about relationships between files instead of just the open tab.

Settings → Features → Codebase Indexing → Enable
Enter fullscreen mode Exit fullscreen mode

This step matters. Without indexing, Cursor only sees the file you have open, which limits its ability to catch cross-component issues like prop drilling.

Step 3: Core Review

Open the chat panel (Cmd/Ctrl + L) and ask targeted questions instead of vague ones.

Good prompt:

Review this component for unnecessary re-renders, missing 
dependency arrays, and prop drilling. Suggest fixes with code.
Enter fullscreen mode Exit fullscreen mode

Vague prompt (avoid this):

Is this code good?
Enter fullscreen mode Exit fullscreen mode

Specific prompts produce specific, actionable diffs.

Step 4: Final Integration

Apply fixes one file at a time and run your test suite after each change. Don't accept a batch of AI-generated diffs across the whole app at once — review incrementally.


The 7 Things Cursor AI Fixed in My React Codebase

1. Missing useEffect Dependencies

Before:

useEffect(() => {
  fetchUserData(userId);
}, []); // userId missing from deps
Enter fullscreen mode Exit fullscreen mode

After (Cursor's fix):

useEffect(() => {
  fetchUserData(userId);
}, [userId]);
Enter fullscreen mode Exit fullscreen mode

Why it matters: the original code only fetched data once, even if userId changed later — a classic stale closure bug that's hard to spot manually.


2. Unnecessary Re-renders from Inline Functions

Before:

<Button onClick={() => handleClick(item.id)} />
Enter fullscreen mode Exit fullscreen mode

After:

const handleItemClick = useCallback(
  (id) => handleClick(id),
  [handleClick]
);

<Button onClick={() => handleItemClick(item.id)} />
Enter fullscreen mode Exit fullscreen mode

Why it matters: inline functions create a new reference on every render, breaking React.memo optimizations on child components.


3. Prop Drilling Through Multiple Components

Before:

<Dashboard user={user}>
  <Sidebar user={user}>
    <UserBadge user={user} />
  </Sidebar>
</Dashboard>
Enter fullscreen mode Exit fullscreen mode

After (Context introduced):

const UserContext = createContext(null);

function Dashboard() {
  return (
    <UserContext.Provider value={user}>
      <Sidebar />
    </UserContext.Provider>
  );
}

function UserBadge() {
  const user = useContext(UserContext);
  return <span>{user.name}</span>;
}
Enter fullscreen mode Exit fullscreen mode

Why it matters: props were passed through components that didn't even use them, just to reach a deeply nested child.


4. Unhandled Promise Rejections in API Calls

Before:

const fetchData = async () => {
  const res = await fetch("/api/data");
  const json = await res.json();
  setData(json);
};
Enter fullscreen mode Exit fullscreen mode

After:

const fetchData = async () => {
  try {
    const res = await fetch("/api/data");
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const json = await res.json();
    setData(json);
  } catch (error) {
    console.error("Failed to fetch data:", error);
    setError(error.message);
  }
};
Enter fullscreen mode Exit fullscreen mode

Why it matters: a failed request was silently swallowed, leaving the UI stuck in a loading state with no error feedback.


5. Missing Cleanup Functions

Before:

useEffect(() => {
  const interval = setInterval(() => refreshToken(), 60000);
}, []);
Enter fullscreen mode Exit fullscreen mode

After:

useEffect(() => {
  const interval = setInterval(() => refreshToken(), 60000);
  return () => clearInterval(interval);
}, []);
Enter fullscreen mode Exit fullscreen mode

Why it matters: without cleanup, the interval kept running after the component unmounted, causing memory leaks and duplicate token refresh calls.


6. Duplicated Logic Across Components

Cursor flagged three separate components with near-identical form validation logic and suggested extracting a custom hook.

function useFormValidation(initialValues, validate) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});

  const handleChange = (e) => {
    setValues({ ...values, [e.target.name]: e.target.value });
  };

  const validateForm = () => {
    const newErrors = validate(values);
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  return { values, errors, handleChange, validateForm };
}
Enter fullscreen mode Exit fullscreen mode

Why it matters: three copies of the same logic meant three places to fix a bug instead of one.


7. Non-Memoized Expensive Computations

Before:

const sortedItems = items.sort((a, b) => a.price - b.price);
Enter fullscreen mode Exit fullscreen mode

After:

const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.price - b.price),
  [items]
);
Enter fullscreen mode Exit fullscreen mode

Why it matters: the original code re-sorted on every render and mutated the original array in place — a double bug that's easy to miss in review.


Common Mistakes Developers Make (Even With AI Help)

  • Blindly accepting every AI suggestion without understanding why the change was made
  • Applying fixes across the whole codebase at once, making it hard to trace a regression
  • Skipping tests after refactors, assuming AI-generated code is automatically correct
  • Not indexing the codebase first, which limits Cursor to single-file context
  • Treating AI review as a replacement for code review, not a supplement to it

AI tools are excellent at pattern recognition, but they don't know your business logic or edge cases. Always review the "why," not just the diff.


Best Practices for Using AI Code Review Tools

  • Review one file or feature at a time, not the entire repo in one pass
  • Always run your existing test suite after applying suggested fixes
  • Use specific, technical prompts — vague prompts produce vague fixes
  • Combine AI review with ESLint rules like react-hooks/exhaustive-deps for continuous enforcement
  • Keep a changelog of AI-suggested refactors so your team can audit decisions later

Visual Explanation (What to Look At)

(Screenshots recommended here for a published version)

  • Screenshot 1: Cursor's chat panel showing a code review prompt and the suggested diff side-by-side
  • Screenshot 2: Before/after folder structure showing the new hooks/ directory after extracting useFormValidation
  • Screenshot 3: React DevTools Profiler showing reduced re-render count after the useCallback and useMemo fixes

Real-World Use Case: Where This Matters Most

These exact issues show up constantly in:

  • SaaS dashboards — where prop drilling and re-renders slow down data-heavy tables
  • Admin panels — where forms are duplicated across multiple entity types
  • Mobile-first React apps — where memory leaks from missing cleanup functions drain battery and performance
  • Production systems with API-heavy UIs — where unhandled promise rejections cause silent failures in customer-facing screens

If your app fits any of these categories, it's worth running an AI-assisted review pass at least once per quarter.


Conclusion

Cursor AI didn't rewrite my architecture or replace my judgment as a developer. What it did was catch 7 specific, common React problems — missing dependencies, unnecessary re-renders, prop drilling, unhandled errors, missing cleanup, duplicated logic, and non-memoized computations — faster than a manual audit would have.

These aren't exotic bugs. They're the kind of small issues that quietly accumulate in every growing React codebase, and catching them early keeps your app fast, maintainable, and easier to onboard new developers onto.

If you're maintaining a React app of any real size, an AI-assisted review pass is a low-effort, high-value habit worth building into your workflow.


Want to Build React Apps Faster with AI?

Learning React is one thing. Building real-world applications efficiently is another.

You can use ChatGPT, Claude, and Cursor to write code, debug issues, refactor components, generate features, and speed up your development but getting useful results depends heavily on how you prompt AI.

That’s why I created The Ultimate React + Cursor Prompt Library (1000+ AI Prompts) a practical collection of AI prompts designed specifically for React developers.

Inside the library, you’ll find 1,000+ practical prompts covering React development, UI components, debugging, refactoring, performance optimization, API integration, state management, testing, architecture, and more.

Each prompt is designed to help you get better results from AI coding assistants like Cursor, ChatGPT, and Claude, so you can spend less time figuring out what to ask and more time building.

Instead of staring at a blank Cursor chat wondering what prompt to write, you can start with proven prompts and adapt them to your own projects.

Whether you’re building a SaaS, freelance project, startup, dashboard, or personal application, this library can help you code faster, solve problems quicker, and get more out of AI-assisted development.

👉 The Ultimate React + Cursor Prompt Library: 1000+ AI Prompts →

Top comments (0)