How to Debug a React App

What you’ll build or solve

You’ll locate the source of a React bug and verify the app behaves correctly again.

When this approach works best

This approach works best when:

  • You see an error or warning in the browser console.
  • A component renders the wrong data or does not update.
  • A click handler runs but the UI does not change.
  • Data loads from an API and something looks missing or stale.

This is a bad idea if your project does not compile. Fix build and syntax errors first, then debug runtime behavior.

Prerequisites

  • A React app running in development
  • Access to browser DevTools
  • Basic comfort reading component props and state

React DevTools helps, but you can still debug without it.


Step-by-step instructions

Step 1: Read error messages in the browser console

Open your app in the browser, then open DevTools and go to the Console tab. React errors usually include:

  • The error message
  • The component name
  • The file and line number

Example:

TypeError: Cannot read properties of undefined (reading 'name')
   at UserCard (UserCard.jsx:12)

Open that file and jump to the line shown.

What to look for

  • Fix the first meaningful error before anything else, later errors often cascade.
  • Look for messages about undefined, null, invalid hook calls, or missing keys.
  • Use the file and line number from the stack trace, not the last line in the output.

Step 2: Inspect values with console.log

Use logging to confirm what values your component receives and what your code runs.

Log props

JavaScript

functionUserCard({ user }) {
console.log("User prop:",user);
return<h2>{user.name}</h2>;
}

Log state around an interaction

import {useState }from"react";

functionCounter() {
const [count,setCount]=useState(0);

functionhandleClick() {
console.log("Before:",count);
setCount(count+1);
  }

return<buttononClick={handleClick}>{count}</button>;
}

Good places to log:

  • Before conditional renders
  • Inside event handlers
  • Inside useEffect callbacks

What to look for

  • Props or state that show up as undefined or an unexpected type.
  • Values that stay the same even after you expect an update.
  • Effects that run more often than expected.

Step 3: Use React Developer Tools to inspect component data

React Developer Tools lets you inspect what React sees, without adding logs everywhere.

  • Install the React Developer Tools browser extension.
  • Open DevTools and switch to the Components tab.
  • Select a component in the tree.

You can inspect:

  • Props passed into the component
  • Current state values
  • Hook values and their current results

What to look for

  • Props that never arrive from the parent component.
  • State that updates in code but does not change in React DevTools.
  • Components re-rendering more than expected when you interact with the UI.

Step 4: Check API calls in the Network tab

If your app loads data from an API, check the Network tab in DevTools.

  • Open DevTools and go to Network.
  • Trigger the action that loads data, such as a page load or button click.
  • Click the request to inspect details.

Check:

  • Status code (200 vs 404/500)
  • Response body and shape
  • Request URL, headers, and query parameters

What to look for

  • 401 or 403 errors that point to auth problems.
  • 404 errors caused by wrong endpoints.
  • CORS errors that block browser requests.
  • Response data that does not match what your UI code expects.

Examples you can copy

Example 1: Find where a prop becomes undefined

functionParent() {
constuser=undefined;
console.log("Parent user:",user);
return<UserCarduser={user}/>;
}

functionUserCard({ user }) {
console.log("UserCard user:",user);
return<h2>{user?.name}</h2>;
}

Use logs at both the parent and child to spot where the value changes.


Example 2: Confirm a click handler fires

import {useState }from"react";

functionLikeButton() {
const [liked,setLiked]=useState(false);

functiontoggle() {
console.log("Clicked, liked was:",liked);
setLiked(!liked);
  }

return<buttononClick={toggle}>{liked?"Liked":"Like"}</button>;
}

If the log never appears, the handler is not wired correctly.


Example 3: Inspect an API response shape

JavaScript

import {useEffect }from"react";

useEffect(() => {
fetch("/api/profile")
.then((res) =>res.json())
.then((data) =>console.log("Profile response:",data))
.catch((err) =>console.error("Profile error:",err));
}, []);

Pair this with the Network tab to confirm status codes and response content.


Common mistakes and how to fix them

Mistake 1: Skipping the first meaningful console error

What you might do:

Start fixing warnings or later errors while the first error still happens.

Why it breaks:

One early error can stop rendering and create a flood of follow-up errors.

Correct approach:

Fix the first meaningful error in the console, then refresh and re-check.


Mistake 2: Mutating state directly

What you might do:

items.push(newItem);
setItems(items);

Why it breaks:

React may not detect changes because the reference stays the same.

Correct approach:

setItems((prev) => [...prev,newItem]);

Mistake 3: Missing dependencies in useEffect

What you might do:

useEffect(() => {
fetchData(filter);
}, []);

Why it breaks:

The effect reads filter but never re-runs when filter changes.

Correct approach:

useEffect(() => {
fetchData(filter);
}, [filter]);

Troubleshooting

If you see Cannot read properties of undefined, log the value and add a guard like user?.name while you trace the source.

If the UI does not update after state changes, check for direct mutation and verify state in React DevTools.

If requests fail, check Network for status codes and CORS errors.

If effects run too often, check dependency arrays and confirm you are not updating state in a way that triggers a loop.

If hot reload acts strangely, restart the dev server.


Quick recap

  • Use the browser console to read the first meaningful error and jump to the file and line.
  • Add console.log where the wrong value might enter your component.
  • Use React DevTools to inspect props, state, and hooks in real time.
  • Use the Network tab to confirm API requests succeed and responses match what your UI expects.
  • Fix one issue at a time, then refresh and re-check.