First React Application and JSX
Introduction
Your first React app mounts a root component into the page and re-renders when state changes. This chapter covers main.tsx, JSX syntax, useState, a click counter, and hot module replacement (HMR) so edits appear instantly.
Prerequisites
- Environment and Create React Project
- Dev server running:
npm run dev
Entry Point: main.tsx
src/main.tsx:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>
);index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>Code explanation:
createRootis the React 18+ API (replaces legacyReactDOM.render)StrictModeruns extra checks in development—effects may run twice on purposetype="module"enables ES imports; Vite bundles for the browser
Root Component App.tsx
src/App.tsx:
Code explanation:
useStatereturns[value, setter]—callingsetCountschedules a re-render{count}embeds JavaScript expressions in JSXonClickuses camelCase (notonclick)classNamereplaces HTMLclasstype="button"avoids accidental form submit behavior
Save the file—the browser updates without a full reload (HMR).
What Is JSX?
JSX looks like HTML inside JavaScript. Vite compiles it to React.createElement calls.
// JSX
const el = <h1 className="title">Hi</h1>;
// Rough compiled output
const el = React.createElement("h1", { className: "title" }, "Hi");Rules:
| HTML | JSX |
|---|---|
class | className |
for | htmlFor |
| Self-closing tags required | <img />, <input /> |
| JavaScript expressions | Wrap in { } |
Use semantic HTML inside JSX—<main>, <button>, not clickable <div>s.
Fragments
A component must return one parent element. Use a Fragment to avoid extra DOM nodes:
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
);Equivalent: <React.Fragment> or <Fragment> with import.
Exporting Components
| Style | Example |
|---|---|
| Default export | export default function App() — import App from "./App" |
| Named export | export function Header() — import { Header } from "./Header" |
This track uses default export for page-level components and named exports for small utilities—match your team convention.
Styling the Root
src/App.css:
.app {
font-family: system-ui, sans-serif;
max-width: 32rem;
margin: 2rem auto;
padding: 1rem;
}
button {
padding: 0.5rem 1rem;
cursor: pointer;
}Global resets live in index.css. Styling React Components covers CSS Modules later.
Compare With Vue SFC
React App.tsx | Vue App.vue | |
|---|---|---|
| Markup | JSX in return | <template> |
| State | useState | ref |
| Events | onClick | @click |
| Styles | import './App.css' | <style scoped> |
FAQ
Why document.getElementById("root")!?
TypeScript thinks getElementById may return null. ! asserts the element exists—ensure index.html has <div id="root">.
Can I put logic before return?
Yes—hooks and helpers go at the top of the function body, before return.
Why StrictMode double effects?
Development-only check for unsafe side effects—see Effects and Strict Mode.
.tsx vs .jsx?
This track uses TypeScript—.tsx for files with JSX.
Variable named React required?
With modern JSX transform, you often do not import React just for JSX—Vite handles it. You still import hooks: import { useState } from "react".