case study

From 14 errors to deployed on Vercel
in 60 minutes.

How Sarah turned a broken React capstone into a portfolio piece she actually put on LinkedIn.

// meet sarah

S

Sarah T.

Bootcamp grad · Career switcher from marketing · 3 months post-graduation

Sarah finished a 14-week full-stack bootcamp. She learned React, Node, and PostgreSQL — enough to build a capstone project. But “enough to build” and “enough to ship” turned out to be very different things.

Her capstone was ForkYeah — a recipe-sharing app where users could post recipes, save favorites, and search by ingredient. It worked in the demo. It worked on her machine. Then she deployed it and everything fell apart.

// before

“It crashes the second it loads. I've been staring at this for 3 weeks.”

Here's exactly what was going wrong when Sarah reached out:

~/forkyeah — Chrome DevTools Console
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
  at RecipeList (RecipeList.jsx:23:1)
  at renderWithHooks (react-dom.development.js:14985)
Warning: Can't perform a React state update on an unmounted component.
  at App (App.jsx:8:1)
GET https://spoonacular-api.com/recipes?apiKey=undefined 401 (Unauthorized)
Uncaught (in promise) SyntaxError: Unexpected token '<' (at fetchRecipes.js:12)
  // tried to JSON.parse an HTML error page
Warning: Each child in a list should have a unique "key" prop.

Bug #1 — Infinite re-render loop crashes the app

App.jsx — the culprit
// Sarah's original code
const [recipes, setRecipes] = useState();
const [search, setSearch] = useState('');

useEffect(() => {
  fetchRecipes(search).then(data => setRecipes(data));
} // ← missing dependency array
// runs on EVERY render → sets state → re-renders → runs again → 💀

No dependency array on the useEffect. Every render triggered fetchRecipes, which called setRecipes, which triggered another render. Infinite loop. The app ate 200+ API calls in seconds and the browser tab froze.

Bug #2 — API calls fail silently and crash the render

fetchRecipes.js
// No error handling. No loading state. No fallback.
async function fetchRecipes(query) {
  const res = await fetch(
    `https://api.spoonacular.com/recipes?query=${query}&apiKey=${API_KEY}`
  );
  return res.json(); // ← crashes if response is HTML error page
}

API_KEY was hardcoded to undefined because she forgot to set up the .env file on the deployed version. The Spoonacular API returned an HTML error page, and res.json() choked on it. No try/catch. No error state. Just a white screen.

Bug #3 — CSS layout breaks on any screen that isn't her laptop

/* RecipeCard.css — the CSS Sarah wrote at 2am */
.recipe-grid {
  display: flex;
  flex-wrap: wrap;
  width: 1200px;  /* ← hardcoded width */
}
.recipe-card {
  width: 380px;  /* ← hardcoded width */
  margin: 10px;
  position: absolute;  /* ← why is this absolute?? */
}
.recipe-card img {
  height: 400px;  /* ← images overflow on mobile */
}

Hardcoded pixel widths everywhere. Cards positioned with position: absolute (probably from a Stack Overflow copy-paste that solved one problem and created five more). On mobile, cards stacked on top of each other and overflowed off-screen.

“I spent 3 weeks Googling every error message. I'd fix one thing and break two more. I started questioning if I actually learned anything at bootcamp. My portfolio has a gap where this project should be, and every job application asks for deployed projects. I was ready to just delete the whole repo and pretend it never existed.”

— Sarah, before her session

// the session

60 minutes. Here's exactly what happened.

0:00

Diagnosis

Sarah screenshared and explained the project. The engineer opened Chrome DevTools — immediately saw the infinite re-render in the Console and the 401 errors in the Network tab. Within 2 minutes, the engineer had identified all 3 core issues and laid out the fix order: state management first, then API, then CSS.

0:05

Fix #1 — Kill the infinite loop

The engineer didn't just add [search] to the dependency array and move on. They pulled up the React docs on useEffect, explained why every render was triggering the effect, and drew the render cycle on a whiteboard. Sarah typed the fix herself:

// ✅ Fixed: dependency array tells React when to re-run
useEffect(() => {
  if (!search) return;
  fetchRecipes(search).then(data => setRecipes(data));
}, [search]);  // ← only re-runs when search changes

They also initialized useState([]) instead of useState() so recipes.map() wouldn't blow up before data loaded.

0:20

Fix #2 — Proper API calls with error handling

The engineer showed Sarah how to set up environment variables properly (.env.local for dev, REACT_APP_ prefix for Create React App). Then they rewrote the fetch together:

// ✅ Fixed: error handling + loading state + env vars
async function fetchRecipes(query) {
  const key = process.env.REACT_APP_SPOONACULAR_KEY;
  if (!key) throw new Error('API key not configured');

  const res = await fetch(
    `https://api.spoonacular.com/recipes?query=${query}&apiKey=${key}`
  );

  if (!res.ok) {
    throw new Error(`API error: ${res.status}`);
  }

  return res.json();
}

They added loading and error states to the UI too — a isLoading spinner and a user-friendly error message instead of a white screen of death.

0:40

Fix #3 — CSS grid that actually works

Ripped out all the hardcoded pixel widths. Replaced the entire layout with 3 lines of CSS Grid:

/* ✅ Fixed: responsive grid in 3 lines */
.recipe-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}

The engineer explained the difference between auto-fill vs auto-fit, when to use minmax(), and why CSS Grid beats Flexbox for card layouts. Sarah removed the position: absolute and set images to object-fit: cover with aspect-ratio: 4/3 so they stopped overflowing.

0:55

Deploy — Ship it live

With 5 minutes left, the engineer walked Sarah through deploying to Vercel: connected her GitHub, set the REACT_APP_SPOONACULAR_KEY environment variable in the dashboard, hit deploy. Build passed. Site went live. They pulled it up on Sarah's phone to test the responsive layout.

// after

Deployed. On her portfolio. On her LinkedIn.

~/forkyeah
sarah:~/forkyeah$ npm run build
Compiled successfully.
  Bundle size: 142kb (gzipped)
sarah:~/forkyeah$ vercel --prod
✓ Production: forkyeah.vercel.app [28s]
sarah:~/forkyeah$ echo "finally."
finally.
0

console errors

60

minutes total

$45

total cost

What Sarah actually learned (not just “got fixed”)

How useEffect dependency arrays work — and how to debug infinite re-renders
The pattern for async data fetching: loading → success → error states
How environment variables work in React and on Vercel
When to use CSS Grid vs Flexbox (and why auto-fill + minmax is magic)
How to deploy to Vercel and set up environment variables in production

“I thought I was dumb for not being able to fix it myself. Turns out my code was 90% there — I just needed someone to show me the 10% I was missing. The engineer didn't make me feel stupid. They made me feel like a real developer who hit a normal wall. I added ForkYeah to my portfolio that night and updated my LinkedIn the next morning. Got my first recruiter message two days later.”

— Sarah T., after her Mergepair session

// sound familiar?

Every bootcamp grad hits this wall.

You learned enough to build something. But shipping it — handling edge cases, debugging production issues, writing CSS that works on more than one screen — that's a different skill. And bootcamps don't teach it.

You're not behind. You just need someone who's been there before to sit next to you and show you the patterns. That's what Mergepair is.

> your turn

Your capstone doesn't have to sit broken.
Let's fix it together.

Start with a $15 diagnostic. A senior engineer will look at your code and tell you exactly what's wrong and how to fix it. If the plan doesn't help — full refund.

Money-back guarantee · No subscription · Sessions within 48 hours