Get eBook BundleVolume I index
The First React Screen

Editing, Reloading, and Reading Errors

Ishtmeet Singh @ishtms/July 20, 2026/10 min read
#react#vite#debugging#errors#source-maps

The project now runs one complete sequence from index.html to visible DOM nodes. Errors follow the same sequence, and I read every error by asking one question first - which stage produced this?

text
read source
  -> resolve imports
  -> transform JSX
  -> evaluate modules
  -> render components
  -> commit DOM
  -> handle later events

A failure at one stage stops later stages from seeing the new code. A JSX syntax error never reaches component rendering. A click-handler error happens after the screen has already rendered fine. And wrong output can pass through every stage without a single exception.

The best way I know to learn this is controlled failures. Break one small thing on purpose, read the report it produces, restore the code, and confirm the page again. This lesson does that for each stage.

Keep Four Reports Available

Four reports tell you what happened, the editor, the terminal, the browser overlay, and the browser console.

The editor can flag source issues before you even save. What it reports depends on installed extensions and project configuration.

The terminal holds the Vite process, so it reports server startup, module resolution, transformation, and build-tool failures.

The browser overlay shows development failures sent by Vite or reported while the page runs. Its whole purpose is to put the current blocking error in front of you.

The console records runtime exceptions, React warnings, browser warnings, and your own logs.

Arrange the editor beside the browser and keep the Vite terminal visible. Open the browser Console panel. Clear old output before each controlled failure, so every report ties to one action.

A Successful Edit Has Observable Steps

First, the healthy case. Change the chapter heading.

jsx
function ChapterHeading() {
  return <h1>The First React Screen, Complete</h1>;
}

Save the file. Vite detects the changed module, transforms it, sends a development update, and the browser shows the new text.

Confirm two results after saving.

  • The terminal accepted the changed module.
  • The browser displayed output from that module.

If the browser did not change, resist classifying it as a React render failure. Confirm that the editor saved the right file, Vite accepted it, and the browser tab is on the printed development URL.

Begin with the First New Error

One invalid line can produce a pile of follow-on reports. A parse failure prevents an import, the missing import leaves an update unavailable, and the overlay stays up. Three symptoms, one cause.

So read the first new report produced after the edit. Look for these parts.

text
error category or message
source file
line and column
nearby source excerpt
stack or import chain when present

The line and column mark where a tool could no longer continue. The actual mistake can sit earlier, especially with a missing quote, brace, parenthesis, or closing tag.

Transform Failure from Invalid JSX

Break the JSX first. Remove the closing h1 tag.

jsx
function ChapterHeading() {
  return <h1>The First React Screen;
}

Vite cannot transform this module into executable JavaScript at all. The terminal and the overlay both report App.jsx with a line and column near the invalid JSX.

The page may keep showing the last valid output behind the overlay. Do not read that as the broken file running. Vite kept the previous valid module because no replacement could be produced.

Restore the closing tag.

jsx
return <h1>The First React Screen</h1>;

Save, and wait for the overlay to clear.

Adjacent return expressions produce another transform failure.

jsx
return (
  <h1>The First React Screen</h1>
  <p>Six lessons</p>
);

One return needs one expression. Wrap the elements in main or another appropriate parent.

Module Resolution Failure

Next, break an import path in main.jsx.

jsx
import App from "./Application.jsx";

No file exists at that relative path, and Vite says so. It failed to resolve the import from main.jsx.

Read a relative import from the importing file's directory. ./Application.jsx means a file beside main.jsx, not beside the project root and not beside your terminal prompt.

Check four facts, in order.

  1. The target file exists.
  2. Every directory and filename uses the stored letter case.
  3. The relative path begins at the importing file.
  4. The written extension matches the file when an extension is included.

Restore the generated import.

jsx
import App from "./App.jsx";

Casing deserves its own deliberate check. A case-insensitive local file system accepts ./app.jsx for a file named App.jsx, and then a case-sensitive deployment machine rejects the same import. Match the stored casing exactly even when your machine accepts the variation.

Module Evaluation Failure

Valid syntax can still fail while the module executes. Keep this class separate from transform failures.

Add a top-level call to a function that does not exist.

jsx
initializeLessons();

export default function App() {
  return <h1>ReactBook</h1>;
}

The JSX transforms fine. Then the browser starts evaluating the module, and JavaScript throws a ReferenceError because no binding named initializeLessons exists.

React never receives the component, because module evaluation stopped before the export completed.

text
module transformed
module evaluation failed
App export was not completed
React could not render the new module

Remove the call. Both this and a component render error surface in the browser runtime, and they are still different stages.

Component Render Failure

Now put an undefined binding inside the component.

jsx
function ChapterHeading() {
  return <h1>{chapterTitle}</h1>;
}

This module loads without complaint, because an unknown variable name is valid JavaScript syntax. The failure waits until React calls ChapterHeading and JavaScript evaluates the expression.

text
ReferenceError: chapterTitle is not defined

Two stacks show up in development. The JavaScript stack records the function calls involved in the exception. React's component stack records the React nesting that led to the component.

text
ChapterHeading
App

Use the JavaScript stack to locate executable source and the component stack to locate the rendered occurrence. They answer different questions.

Define the binding before use.

jsx
function ChapterHeading() {
  const chapterTitle = "The First React Screen";
  return <h1>{chapterTitle}</h1>;
}

When reading the JavaScript stack, open the first useful frame from your src directory. Frames inside React and Vite describe library code around the error, and the repair almost always begins at the source expression that supplied the invalid operation.

A Component Can Throw a Deliberate Error

Errors also work for you. A component can reject an invalid requirement on purpose.

jsx
function ChapterHeading({ title }) {
  if (!title) {
    throw new Error("ChapterHeading requires title");
  }

  return <h1>{title}</h1>;
}

Render it without the input.

jsx
<ChapterHeading />

The message names the requirement, and the component stack names the failed occurrence. Restore a title after reading the report.

jsx
<ChapterHeading title="The First React Screen" />

The difference from the earlier failures is intent. This exception is your own contract check, and the development overlay displays its report.

Event Handler Failure

A page can render perfectly and fail only when someone interacts with it.

jsx
function ContinueButton() {
  function handleClick() {
    openNextLesson();
  }

  return <button onClick={handleClick}>Continue</button>;
}

The component renders, because defining handleClick does not run its body. Click the button, and JavaScript reports that openNextLesson is not defined.

Notice that the screen stays visible. React calculated the component tree without any problem. What failed is an event callback, after commit, in response to the click.

Warnings Can Leave Visible Output

React can warn without aborting a render. A list with missing keys stays visible while the console explains that React cannot identify its items reliably across updates.

So a visible page does not prove a clean console. Read warnings and follow the named component before continuing.

And do not silence warnings with broad console filters. Repair the reported code, and later reports stay visible.

Wrong Output Without an Error

The last failure class produces no report at all.

jsx
const total = 6;
const completed = 2;

function LessonProgress() {
  return <p>{total - completed} lessons complete</p>;
}

The page displays 4 lessons complete. Every tool parsed, resolved, evaluated, rendered, and committed this code without complaint. The expression is wrong anyway. It calculates the remaining count while the sentence claims completion.

jsx
return <p>{completed} lessons complete</p>;

When several values feed a calculation, use a temporary console log or a debugger breakpoint, and React DevTools for props and state. Remove temporary logs once the value source is found.

Correct DOM with Wrong Presentation

Correct DOM can still show a wrong screen. The Elements panel displays the right heading with the right class while CSS hides it.

css
.chapter-title {
  color: transparent;
}

React completed its work. The browser then applied a CSS value that made the text invisible.

Inspect the element and its computed styles. An absent class points back at component output. A wrong computed rule points at the stylesheet and cascade. Either way, you avoid rewriting React code for a styling failure.

Source Maps Point Back to JSX

The browser executes transformed JavaScript, and yet stack frames open src/App.jsx. Development source maps make that connection. Vite maps generated positions back to your original files, so keep source maps active during development.

Production source maps are a deployment decision. Publicly served maps expose application source to anyone who asks for them. Uploading maps privately to an error-monitoring service keeps the debugging value without serving them to every browser.

Reload, Restart, or Repair

Match the operation to the failed layer, and pick the smallest one.

Repair and save for source syntax, missing bindings, wrong expressions, and local import paths.

Reload the browser to test a clean client start or to clear state preserved by development updates.

Restart Vite after dependency installation, selected configuration changes, environment-file changes, or a stopped server process.

Reinstall dependencies only when installation state or package resolution is involved. A missing JSX close tag gains nothing from another npm install.

text
source failure  -> repair source
stale page state -> reload page
server input changed -> restart Vite
package state failed -> inspect npm installation

Use One Repair Routine

Use this sequence after every new failure.

  1. Reproduce it with one save, load, or interaction.
  2. Read the first new report.
  3. Identify the stage that produced it.
  4. Open the first relevant application source location.
  5. State what value or syntax was expected there.
  6. Make the smallest repair that restores the requirement.
  7. Save and confirm the report clears.
  8. Repeat the original action.
  9. Perform one clean browser reload.

Step 6 is the one I want you to respect. Unrelated cleanup mixed into a bug repair makes the change unreadable, and the refactor deserves its own review anyway.

Check the Full Trace

Finish by tracing the running screen with no skipped layers.

text
index.html creates div#root
main.jsx finds that DOM node
createRoot creates one React root
root.render receives an App element
React calls App and nested components
JSX produces React element descriptions
React DOM commits host nodes
the browser applies CSS and paints

You can now also place a failure at any point in that trace - before transform, during import resolution, during module evaluation, during component render, after an event, or in visible application logic that never throws.

Sources