AI Coding Agents in React Native: What Changed After We Used Them in Production

8 min read
Share:

Introduction

A settings screen that normally took most of a day was built in under an hour using an AI coding agent. This made us explore tools like Cursor, GitHub Copilot, and Claude Code in a real React Native sprint.

The goal wasn’t just to see if AI could write code, but to determine whether it could reliably handle repetitive development work—navigation, forms, and boilerplate—without introducing more complex issues in architecture, async logic, or native iOS/Android behavior.

This post is that experience report: what worked, what didn’t, where the tooling actively cost us time, and what our review discipline looks like now as a result.

Body
The First Real Test
The first serious trial was a settings screen with form state, validation, loading states, and an API integration gated behind backend feature flags — not a toy example. The engineer wrote a prompt that specified field shapes, the expected payload contract, failure behavior per field, and which existing design-system components to reuse rather than reinvent.

The first draft came back in minutes. It wasn’t production-ready out of the box — error handling defaulted to a generic toast instead of our app’s inline-error convention — but the skeleton was structurally sound, and correcting it took ten minutes instead of an afternoon spent typing boilerplate from scratch. That ratio — a fast, roughly-right first pass versus a slow, correct-from-scratch one — turned out to be the recurring pattern across the sprint, not the exception.

Where AI Agents Actually Helped
Untangling Inherited Code
We’d inherited a navigation stack from a previous contractor, with no design doc and half the original authors gone. Asking the agent to trace how a specific screen was reached — which stack, which params were passed at each hop, where a piece of state actually originated versus where it was just read — produced a working map instead of an afternoon of manual grep-and-guess. It wasn’t fully accurate on the first pass (it missed a conditional redirect buried in a useEffect), but a map that’s 85% right and needs verification beats no map, especially when the alternative is reconstructing five years of undocumented decisions by hand.

Debugging a Stubborn Re-Render Issue
We had a list screen re-rendering more than it should have, and the usual suspects — inline prop functions, missing useCallback — weren’t the cause. After describing the symptom and sharing the component tree, the agent correctly pointed to a context provider higher up the tree that was recreating its value object on every render:

// Before — new object on every render
<MyContext.Provider value={{ user, settings }}>

// After — memoized so children don’t re-render unnecessarily
const contextValue = useMemo(() => ({ user, settings }), [user, settings]);
<MyContext.Provider value={contextValue}>

We still verified the fix with the profiler ourselves, but the time to find the lead was a fraction of what it normally takes.
Closing the Test-Coverage Gap
Tests are the first thing to get deprioritized under deadline pressure, which most teams will admit to. We started using the agent specifically to scaffold Jest and React Native Testing Library tests for components that were already finished. It defaults to happy-path coverage and misses edge cases unless explicitly prompted for them, but going from zero tests to a reasonable baseline — then refining manually — beat staring at an empty test file.

Where It Fell Short
Missing Business Context
One of our screens has a field that’s optional for most users but required depending on subscription tier — a rule that came out of a support escalation, not anything visible in the code. The agent had no way to know that, and its first draft treated the field as universally optional. Not a flaw in the tool; just a reminder that business context lives in tickets and people’s heads, not the codebase alone.

Small Architectural Drift
A few times, generated code introduced a slightly different pattern than the rest of the file used — handling loading state with a boolean instead of the status enum (‘idle’ | ‘loading’ | ‘error’ | ‘success’) the rest of the screen relied on. Functionally fine, but the kind of inconsistency that compounds if it isn’t caught in review.

The Temptation to Skip Review
This was the most important lesson. Early on, an engineer accepted a generated API integration without reading it closely, and it shipped with a missing null check that only surfaced when a particular response came back without an optional field. Nothing catastrophic, but a clear signal that generated code needs the same scrutiny as any teammate’s pull request.

 Challenges We Ran Into
Build issues: Suggested fixes often addressed symptoms rather than root causes, so issues reappeared in clean builds or CI.
Dependency conflicts: Some upgrades fixed one issue but introduced new peer/dependency problems, requiring additional investigation.
Platform-specific gaps: AI performed well with JS/TS but struggled with native iOS/Android issues like CocoaPods, Gradle, and native crash debugging.
Confident wrong answers: Tools often provided fixes without clearly indicating uncertainty, making independent verification essential.
Context loss: Long sessions sometimes caused previously stated constraints or decisions to be forgotten.
Key takeaway: AI assistance is valuable, but “the agent says it’s fixed” should be treated as a hypothesis, not a verified state.

Tool Comparison: Claude Code vs. Cursor vs. GitHub Copilot
This wasn’t a formal benchmark — no controlled task set, no scoring rubric — it’s a working comparison from using all three inside the same React Native codebase over the same sprint, which is a fairer comparison than most vendor case studies offer but still an anecdotal one.

How Our Workflow Looks Now
A few habits made the difference between useful output and wasted time:

Write the requirement out properly first — fields, API behavior, edge cases — rather than a one-line prompt and hoping for the best.
Treat the first output as a draft, reviewed the same way as a teammate’s PR, checked against existing patterns before merging.
Lean on it heavily for repetitive, low-judgment work: test scaffolding, boilerplate forms, documentation, multi-file refactors.
Keep ownership unchanged — if something breaks in production, it’s on the team, not the tool, which is what keeps the review step from becoming optional.

Criteria Claude Code Cursor GitHub Copilot
Multi-file / whole-codebase reasoning Strongest of the three — best at tracing logic across navigation stacks, contexts, and state ori Strong, aided by its codebase indexing Weakest here; optimized for local/single-file context
Following existing patterns (design system, status enums) Good when the pattern is referenced explicitly in the prompt Good, especially with .cursorrules defined Inconsistent without repeated, explicit prompting
Debugging from a symptom description Strongest in our test — correctly isolated the context-provider re-render issue from a description alone Solid, benefits from live in-editor context Limited — better suited to line-level completion than root-cause analysis
Native build / platform-specific issues Weak — shared blind spot across all three Weak Weak
Test scaffolding Good happy-path coverage; edge cases need explicit prompting Similar strength and same caveat Decent for simple, low-branching components
Editor integration CLI-first, editor-agnostic Deepest integration — it is the editor Deepest integration with VS Code / JetBrains; most mature autocomplete of the three

Our take, after nine years of watching tooling promises come and go: there’s no single winner here because the three tools aren’t competing for the same moment in the workflow.

For investigative or cross-file work — tracing inherited navigation logic, root-causing a re-render bug, scoping a refactor — Claude Code was the strongest performer in our test, largely because it held broader context without needing the whole codebase open in an editor.
For a tight, low-friction in-editor loop, Cursor was the most natural day-to-day tool — it minimizes context-switching in a way that matters more than raw capability during normal feature work.
For fast inline autocomplete while writing routine code, GitHub Copilot remains the most mature and least disruptive to an existing VS Code or JetBrains setup, particularly for teams not ready to change their editor or workflow.
In practice, most engineers on the team ended up using more than one tool rather than standardizing on a single winner — Cursor or Copilot for moment-to-moment typing, Claude Code when a task needed broader codebase context or a longer investigative back-and-forth. None of the three reliably solved native build or platform-specific issues, which stayed a manual debugging skill regardless of which agent was in the loop — a reminder that “AI-assisted” doesn’t yet mean “AI-covered” for the parts of mobile development closest to the metal.

Conclusion

For our team, AI coding agents earned their place — not by replacing anyone’s job or doubling our output across the board, but by absorbing the repetitive, low-judgment work that used to eat into everyone’s day. That freed up real time for the parts of the job that still need a human: deciding what to build, understanding why users behave a certain way, and making the calls no prompt can make for you.

Leave a Reply

Your email address will not be published. Required fields are marked *