React: Setting Up the Environment and JSX
Last updated: 2026-08-26
Writing React code is like renovating a house—Vite is the construction crew (it helps you set up the scaffolding and the development servidor), and JSX is the blueprint (a syntax for writing HTML within JavaScript). In this lesson, you’ll build your first React project from scratch.
1. What You'll Learn
- Quickly Create a React Project Using Vite
- Project Directory Structure and the Purpose of Each File
- JSX Syntax Rules (Expressions, Conditions, Lists)
- Key Differences Between JSX and HTML
- Installing and Using React DevTools
2. A True Story of a Beginner Developer
(1) Pain Point: It took a whole day to set up the environment
Bob has just learned JavaScript and wants to try React. He searched online for tutorials, and some people recommended Create React App, others recommended Vite, and still others recommended Next.js. He randomly chose CRA and started the installation:
npx create-react-app my-app
Results:
- Installation took 8 minutes (downloading over 200 MB of dependencies)
- It took 30 seconds to start the development server
- The project directory is filled with over 35,000 files (node_modules)
- Changing a single line of code causes the page to take 2–3 seconds to refresh
Bob was frustrated: "I haven't even started writing code, and I've already wasted an hour."
(2) Solution using Vite and React
Create the same project using Vite:
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
| Comparison | CRA | Vite |
|---|---|---|
| Installation Time | ~8 minutes | ~30 seconds |
| Startup time | ~30 seconds | < 1 second |
| Hot Module Replacement (HMR) | 2–3 seconds | <50 ms |
| Build Time | ~60 seconds | ~10 seconds |
| node_modules size | ~200MB | ~80MB |
Benefits: It took Bob just 3 minutes from installation to seeing "Hello World," and the hot updates are so fast that you hardly notice the wait.
3. Core Rules of JSX
JSX stands for JavaScript XML. It is not HTML, but rather a syntax extension for JavaScript. Each JSX expression is ultimately compiled into a React.createElement() call.
graph LR
A[JSX Code] --> B[Babel Compilation]
B --> C[React.createElement]
C --> D[Virtual DOM Object]
D --> E[True DOM]
style A fill:#61dafb,color:#000
style C fill:#ff6b6b,color:#fff
(1) Single-Element Rule
JSX expressions must have a root element. They cannot return two sibling elements side by side.
// ❌ Error:No root element
return (
<h1>Title</h1>
<p>Paragraph</p>
)
// ✅ Correct:Use one <div> Package
return (
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
)
// ✅ You can also use React Fragment(<></>),Does not incur additional DOM
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
)
(2) Embedding JavaScript Expressions in JSX
Use brackets {} to embed any JavaScript expression:
const name = 'Alice'
const age = 28
const colors = ['red', 'green', 'blue']
// Variable
<h1>Hello, {name}!</h1>
// Expression Evaluation
<p>Next year {age + 1} years old</p>
// Ternary Operator
<span>{age >= 18 ? 'Adulthood' : 'Minor'}</span>
// Function Call
<p>Today's Date:{new Date().toLocaleDateString()}</p>
// Array Length
<p>Total {colors.length} A Color</p>
(3) Quick Reference Chart: Differences Between JSX and HTML
| Feature | HTML | JSX |
|---|---|---|
| Class Name | class="box" |
className="box" (class is a JavaScript reserved word) |
| Tag Attribute | for="input" |
htmlFor="input" (for is a JavaScript reserved word) |
| Inline Styles | style="color:red" |
style={{ color: 'red' }} (object syntax) |
| Boolean Property | disabled |
disabled={true} or disabled |
| Self-closing tags | <br> <img> |
Must be closed: <br /> <img /> |
| Note | <!-- comment --> |
{/* comment */} |
| Event binding | onclick="handle()" |
onClick={handle} |
| CSS Property Name | font-size (hyphen) |
fontSize (camelCase) |
▶ Example: JSX vs. HTML Comparison
Output:
Side-by-side comparison: HTML syntax vs JSX syntax showing equivalent markup
// ============================================
// Example:The Same Card,HTML vs JSX Comparison of Writing Styles
// ============================================
// ---- HTML Writing Style ----
<div class="card" style="background-color: #f0f0f0; padding: 20px;">
<!-- TODO: 替换为实际用户头像图片 -->
<img src="https://i.pravatar.cc/80" alt="Avatar" class="avatar">
<label for="name">Name:</label>
<input type="text" id="name" disabled>
<!-- This is a comment. -->
<button onclick="handleClick()">Click</button>
</div>
// ---- JSX Writing Style ----
<div className="card" style={{ backgroundColor: '#f0f0f0', padding: '20px' }}>
<!-- TODO: 替换为实际用户头像图片 -->
<img src="https://i.pravatar.cc/80" alt="Avatar" className="avatar" />
<label htmlFor="name">Name:</label>
<input type="text" id="name" disabled={true} />
{/* This is a comment. */}
<button onClick={handleClick}>Click</button>
</div>
Output:
Displays: "` `"
4. Creating a React Project with Vite
(1) Environmental Requirements
| Tool | Version Requirements | Check Command | Installation Method |
|---|---|---|---|
| Node.js | ≥ 18.0 | node -v |
nodejs.org |
| npm | ≥ 9.0 | npm -v |
Installed automatically with Node.js |
| Editor | Any | — | Recommended: VS Code |
(2) Create a project and start it
# 1. Create a Project(react-ts = React + TypeScript Template)
npm create vite@latest my-react-app -- --template react-ts
# 2. Go to the project directory
cd my-react-app
# 3. Install Dependencies
npm install
# 4. Start the development server
npm run dev
Output:
VITE v5.x ready in 320ms
➜ Local: http://localhost:5173/
➜ Network: http://192.168.1.100:5173/
Open http://localhost:5173/, and you should see the default welcome page for Vite + React.
(3) Project Directory Structure
my-react-app/
├── index.html # Entrance HTML Documents(Vite Parsing Entry Point)
├── package.json # Project Configuration and Dependencies
├── vite.config.ts # Vite Profile
├── tsconfig.json # TypeScript Layout
├── tsconfig.app.json # Applications TS Layout
├── tsconfig.node.json # Node.js Environment TS Layout
├── public/ # Static Resources(Will not be compiled)
│ └── vite.svg
└── src/ # Source Code Directory
├── main.tsx # App Entry Point(Render the root component)
├── App.tsx # Root Component
├── App.css # Root Component Styles
├── index.css # Global Styles
└── assets/ # Resource Files(will be compiled)
└── react.svg
| File | Purpose |
|---|---|
index.html |
Page entry point; Vite begins parsing here |
src/main.tsx JavaScript entry, render <App /> to #root |
|
src/App.tsx |
Root component; all other components start here |
vite.config.ts |
Vite Configuration (Aliases, Proxies, Plugins, etc.) |
▶ Example: Creating the Simplest React Component
Output:
Renders a minimal React component (e.g., <App />) displaying content in the browser
// ============================================
// Example:from main.tsx The Complete Process for Navigating to the Page
// ============================================
// src/main.tsx —— App Entry Point
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>
)
Output:
Heading: "Hello, React!". Displays: "Hello, React!"
// src/App.tsx —— Root Component
function App() {
return (
<div>
<h1>Hello, React!</h1>
<p>This is my first one React Applications 🎉</p>
</div>
)
}
export default App
/* src/index.css —— Global Styles */
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
text-align: center;
}
5. React DevTools
React DevTools is an essential tool for debugging React applications, allowing you to view the component tree, props, state, and performance.
| Installation Method | Procedure |
|---|---|
| Chrome Extension | Chrome Web Store search "React Developer Tools" |
| Firefox Extension | Firefox Add-ons search "React Developer Tools" |
| Standalone App | npx react-devtools |
▶ Example: Viewing a component using DevTools
Output:
DevTools shows component tree with props/state. Inspect <App > → nested components with their current props and state values
After installation, open the Developer Tools (F12), and you'll see two new tabs: Components and Profiler:
// in DevTools You can view these components in real time here Props and State
function App() {
const [count, setCount] = React.useState(0)
return (
<div>
<Header title="Counter" />
<Counter count={count} onIncrement={() => setCount(c => c + 1)} />
<Footer year={2026} />
</div>
)
}
// Components The panel will display:
// ├── App
// │ ├── Header (props: { title: "Counter" })
// │ ├── Counter (props: { count: 0, onIncrement: fn })
// │ └── Footer (props: { year: 2026 })
Output:
DevTools shows component tree with props/state. Inspect <App > → nested components with their current props and state values
▶ Example 4: JSX Conditional Rendering and Lists Combined
Output:
Conditional + list: "Loading..." / "Error: ..." / "No products found" / Product grid with name, price, stock status
function ProductCatalog({ products, isLoading, error }) {
if (isLoading) return <p style={{ textAlign: 'center', padding: 40 }}>Loading products...</p>
if (error) return <p style={{ color: '#ff4d4f', textAlign: 'center' }}>Error: {error}</p>
if (products.length === 0) return <p style={{ textAlign: 'center', color: '#999' }}>No products found</p>
return (
<div style={{ maxWidth: 600, margin: '0 auto' }}>
<h2>Product Catalog ({products.length})</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))', gap: 16 }}>
{products.map(product => (
<div key={product.id} style={{ border: '1px solid #eee', borderRadius: 8, padding: 12 }}>
<h4 style={{ margin: '0 0 8px' }}>{product.name}</h4>
<p style={{ color: '#ff4d4f', fontWeight: 'bold', margin: '0 0 4px' }}>${product.price}</p>
{product.inStock ? (
<span style={{ color: '#52c41a', fontSize: 12 }}>In Stock</span>
) : (
<span style={{ color: '#999', fontSize: 12 }}>Out of Stock</span>
)}
</div>
))}
</div>
</div>
)
}
function CatalogPage() {
const sampleProducts = [
{ id: 1, name: 'Keyboard', price: 79, inStock: true },
{ id: 2, name: 'Mouse', price: 49, inStock: true },
{ id: 3, name: 'Monitor', price: 399, inStock: false },
]
return <ProductCatalog products={sampleProducts} isLoading={false} error={null} />
}
Output:
Product catalog (3 items): Keyboard $79 In Stock, Mouse $49 In Stock, Monitor $399 Out of Stock. Grid layout with stock status badges.
▶ Example 5: Comprehensive—Analyzing the React Project Entry File
Output:
Subheading: "Product Catalog ({products.length})". Displays: "Loading products..."
// package.json Key Dependencies
// {
// "dependencies": { "react": "^18.3", "react-dom": "^18.3" },
// "devDependencies": { "vite": "^5.0", "@types/react": "^18.3", "@types/react-dom": "^18.3" }
// }
// src/main.jsx - App Entry Point
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
)
// src/App.jsx - Root Component
import { useState } from 'react'
function App() {
const [currentPage, setCurrentPage] = useState('home')
return (
<div style={{ fontFamily: 'sans-serif', maxWidth: 800, margin: '0 auto', padding: 20 }}>
<nav style={{ display: 'flex', gap: 16, marginBottom: 24, borderBottom: '2px solid #1890ff', paddingBottom: 12 }}>
{['home', 'about', 'contact'].map(page => (
<button key={page} onClick={() => setCurrentPage(page)}
style={{
padding: '8px 16px', border: 'none', borderRadius: 4, cursor: 'pointer',
background: currentPage === page ? '#1890ff' : '#f0f0f0',
color: currentPage === page ? 'white' : '#333',
}}>
{page.charAt(0).toUpperCase() + page.slice(1)}
</button>
))}
</nav>
<main>
{currentPage === 'home' && (
<div>
<h1>Welcome to React</h1>
<p>This is a minimal React app with Vite. Edit src/App.jsx and save to reload.</p>
<p>Current time: {new Date().toLocaleTimeString()}</p>
</div>
)}
{currentPage === 'about' && (
<div>
<h2>About</h2>
<p>Built with React 18 + Vite for fast development and HMR.</p>
</div>
)}
{currentPage === 'contact' && (
<div>
<h2>Contact</h2>
<p>Email us at hello@example.com</p>
</div>
)}
</main>
<footer style={{ marginTop: 40, paddingTop: 12, borderTop: '1px solid #eee', color: '#999', fontSize: 13 }}>
© 2026 React Tutorial. Built with Vite + React 18.
</footer>
</div>
)
}
export default App
Output:
Nav bar (Home/About/Contact). Home: "Welcome to React" + current time. About: "Built with React 18 + Vite". Contact: "Email us at hello@example.com". Footer: © 2026
❓ FAQ
npm create vite@latest and npx create-vite?npm create vite@latest is the recommended syntax for npm (introduced in npm v7+), which automatically finds and runs the latest create-vite package. npx create-vite can also be used. If you’re using pnpm or yarn, you can use pnpm create vite or yarn create vite.class in JSX—why do we have to use className?class is a reserved keyword in JavaScript. Since JSX is essentially JavaScript, we cannot use class. During rendering, React automatically converts className to the HTML attribute class. Similarly, for → htmlFor.style attribute in JSX use double curly braces {{}}?style={{ color: 'red' }} means: passing a JS object { color: 'red' } as the value of the style attribute..tsx files can contain JSX syntax (i.e., you can write HTML tags in TypeScript), while .ts files cannot. All files containing React components should have the .tsx suffix. Pure logic files (such as utility functions and type definitions) can use the .ts extension.📖 Summary
- Use
npm create vite@latest my-app -- --template react-tsto quickly set up a React + TypeScript project - JSX is not HTML, but an extension of JavaScript syntax: Use
classNameinstead ofclass, and use{}to embed expressions - Every JSX expression must have a root element (which can be a
<></>fragment) - Vite is more than 10 times faster than CRA; this tutorial uses Vite throughout.
- React DevTools is an essential debugging tool that allows you to view the component tree and state
📝 Exercises
- Basic Exercise (Difficulty ⭐): Create a new React + TypeScript project using Vite, and modify
App.tsxto display your name and a brief self-introduction. - Exercise (Difficulty: ⭐⭐): Create a variable named
const isLoggedIn = truein the App component, and use the ternary operator in JSX to display either “Welcome back” or “Please log in.” - Investigation (Difficulty: ⭐): Open the Components panel in React DevTools, view the component tree structure of the Vite default template, and take a screenshot to save it.