Understanding the React Project

We already replaced the Vite boilerplate with the simplest possible React app in the previous section. Let’s take a closer look at what we have and how it all fits together.

package.json

Open package.json and look at the dependencies:

{
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^5.1.1",
    "vite": "^7.3.1"
  }
}

Notice the two sections:

  • dependencies — packages that are part of your app and ship to the browser. react is the core library that lets you define components and manage state. react-dom connects React to the browser’s DOM — it takes React’s output and renders it into actual HTML elements on the page. They are separate packages because React can also render to other targets (like mobile apps with React Native), but for web apps you always need both.

  • devDependencies — packages used only during development, not shipped to the browser. vite is our build tool and dev server. @vitejs/plugin-react enables Vite to transform JSX into regular JavaScript.

index.html

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>

This is the single HTML page for our entire app. The <div id="root"> is an empty container. React fills it with our UI. The <script> tag loads our JavaScript entry point.

main.jsx — Mounting the App

Open src/main.jsx:

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

This is where React connects to the DOM. Here is what is happening:

  1. document.getElementById("root") retrieves the empty <div> from index.html
  2. createRoot(...) creates a React root — the place where React manages the DOM
  3. .render(...) tells React to render the App component inside that root

From this point on, React controls everything inside that <div>. It creates, updates, and removes DOM elements as needed. You write the components, and React does the work on the DOM.

StrictMode is a development helper that warns you about potential problems in your code. It does not render anything visible and has no effect in production.

App.jsx — Your First Component

Open src/App.jsx:

export default function App() {
  return (
    <div>
      <h1>Hello, World!</h1>
    </div>
  );
}

A React component is a JavaScript function that returns JSX. The App function above is a component — it describes what should appear on the screen.

Pay close attention to the return statement. It looks like HTML, but it is not a string. It is JSX. Notice the file extension is .jsx. This tells Vite to transform the JSX before sending it to the browser.

What is JSX?

The HTML-like syntax inside the return statement is called JSX (JavaScript XML). It looks like HTML, but it does things that HTML cannot do. JSX gets transformed into React.createElement() calls behind the scenes. (Modern tools like Vite usually use the newer automatic JSX runtime under the hood, but it serves the same purpose: turning JSX into JavaScript.) When you write:

<h1>Hello, World!</h1>

It becomes something like:

React.createElement("h1", null, "Hello, World!");

This returns a React element — a plain JavaScript object that describes what should appear on the screen. JSX is just a more readable way to create these elements.

Unlike innerHTML strings, JSX gives you syntax highlighting, auto-completion, and compile-time error checking.