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



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:

BASH
npx create-react-app my-app

Results:

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:

BASH
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.

100%
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.

JSX
// ❌ 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>
  </>
)
▶ Try it Yourself

(2) Embedding JavaScript Expressions in JSX

Use brackets {} to embed any JavaScript expression:

JSX
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>
▶ Try it Yourself

(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:

TEXT 📖 Display only
Side-by-side comparison: HTML syntax vs JSX syntax showing equivalent markup
JSX
// ============================================
// 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>
▶ Try it Yourself

Output:

TEXT 📖 Display only
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

BASH
# 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:

TEXT 📖 Display only
  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

BASH
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:

TEXT 📖 Display only
Renders a minimal React component (e.g., <App />) displaying content in the browser
TSX
// ============================================
// 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:

TEXT 📖 Display only
Heading: "Hello, React!". Displays: "Hello, React!"
TSX
// 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
CSS
/* 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:

TEXT 📖 Display only
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:

JSX
// 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 })
▶ Try it Yourself

Output:

TEXT 📖 Display only
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:

TEXT 📖 Display only
Conditional + list: "Loading..." / "Error: ..." / "No products found" / Product grid with name, price, stock status
JSX
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} />
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
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:

TEXT 📖 Display only
Subheading: "Product Catalog ({products.length})". Displays: "Loading products..."
JSX
// 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:

TEXT 📖 Display only
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

Q What is the difference between npm create vite@latest and npx create-vite?
A They have exactly the same functionality. 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.
Q Why can’t we use class in JSX—why do we have to use className?
A Because 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, forhtmlFor.
Q Why does the style attribute in JSX use double curly braces {{}}?
A The outer curly braces indicate "a JavaScript expression embedded in JSX," while the inner curly braces indicate "this is a JavaScript object." Therefore, style={{ color: 'red' }} means: passing a JS object { color: 'red' } as the value of the style attribute.
Q What is the difference between .tsx and .ts files in a project?
A .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.
Q What’s the difference between Vite and Webpack? Why did the tutorial choose Vite?
A Vite uses native ES Modules for its development server, enabling millisecond-level cold starts; Webpack needs to bundle the entire application before starting up, so the larger the project, the slower it becomes. Vite’s HMR (Hot Module Replacement) is also faster because it only needs to replace the modified modules. For production builds, both use Rollup/esbuild for bundling, so there’s not much difference in performance. Vite was chosen for this tutorial because it offers a better development experience and represents a new trend in the React community.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty ⭐): Create a new React + TypeScript project using Vite, and modify App.tsx to display your name and a brief self-introduction.
  2. Exercise (Difficulty: ⭐⭐): Create a variable named const isLoggedIn = true in the App component, and use the ternary operator in JSX to display either “Welcome back” or “Please log in.”
  3. 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.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏