You've set up your development environment and created your first React app. Now it's time to understand what you've created! In this lesson, we'll explore how React apps work, break down the code that Vite generated for us, and build our very first custom component from scratch. By the end, you'll have a solid understanding of how React applications come to life.
Running Your App
If you haven't already, let's start your React app. Open your terminal in your project folder and run:
npm run devYou should see output telling you that your app is running, usually at http://localhost:5173. Open this URL in your browser and you'll see the default Vite + React starter page with a counter button.
💡 Keep the Server Running
Leave this terminal window open while you're developing. The development server needs to keep running for your app to work. To stop it, press Ctrl + C in the terminal.
How React Apps Start
Let's understand the journey from typing npm run dev to seeing your app in the browser. It all starts with three key files:
1. index.html - The Entry Point
Open index.html in your project root. It's surprisingly simple:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>Notice two critical things:
<div id="root"></div>- This empty div is where your entire React app will be injected<script type="module" src="/src/main.jsx">- This loads your JavaScript/React code
That's it! The HTML file is minimal because React will dynamically create everything else using JavaScript.
2. main.jsx - Connecting React to HTML
Open src/main.jsx. This file is the bridge between your HTML and React:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)Let's break down what's happening here:
- Import React libraries:
import React from 'react'brings in React itself - Import ReactDOM:
import ReactDOM from 'react-dom/client'brings in the library that connects React to the browser's DOM - Import your App component:
import App from './App.jsx'brings in your main App component - Import global styles:
import './index.css'loads CSS that applies to your whole app - Create root and render:
ReactDOM.createRoot()finds the div with id "root" and tells React to render your App component inside it
What is React.StrictMode?
<React.StrictMode> is a tool that helps you write better React code. It activates additional checks and warnings during development (but doesn't affect your production build). It's like having a helpful coach that points out potential problems!
3. App.jsx - Your Main Component
Open src/App.jsx. This is where the magic happens - your actual React component:
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export default AppThis might look intimidating at first, but it's actually quite straightforward. Let's break it down piece by piece.
Anatomy of a React Component
A React component is just a JavaScript function that returns what should appear on the screen. Let's analyze the App component:
The Imports Section
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'useState- A React Hook that lets you add state to your component (we'll learn more about this soon!)reactLogoandviteLogo- Importing image files to use in the component./App.css- Component-specific styles
The Component Function
function App() {
const [count, setCount] = useState(0)
return (
// JSX code here
)
}- Function name starts with capital letter: In React, component names MUST start with a capital letter. This is how React distinguishes components from regular HTML tags.
- useState(0): Creates a piece of state called
count, starting at 0, and a functionsetCountto update it. - return statement: Returns JSX - a special syntax that looks like HTML but is actually JavaScript.
The JSX Return
The return statement contains JSX - JavaScript XML. It looks like HTML but has some important differences:
- Use
classNameinstead ofclass(because class is a reserved word in JavaScript) - Use
onClickinstead ofonclick(camelCase for event handlers) - Wrap everything in a single parent element, or use fragments
<>...</> - Use curly braces
{}to embed JavaScript expressions
The Export Statement
export default AppThis makes the App component available for other files to import. That's how main.jsx was able to import App from './App.jsx'!
Visualizing Component Structure
Let's visualize how the App component is structured. Remember, components can contain other components and HTML elements:
Default App Component Structure
See how the App component contains a div, which contains an h1 and other elements? This hierarchical structure is fundamental to React - we build complex UIs by composing simple components together.
Creating Your First Component
Let's create something from scratch! We'll replace the default app with a simple personalized greeting. This will help you understand how components work.
Step 1: Clean the Slate
Open src/App.jsx and replace everything with this simple code:
function App() {
return (
<div>
<h1>Hello, World!</h1>
<p>Welcome to my first React app!</p>
</div>
)
}
export default AppSave the file and look at your browser. The page should update instantly to show your new content! That's Vite's Hot Module Replacement in action.
🎉 Your First Component!
Congratulations! You just created your first React component from scratch. It's simple, but it demonstrates the core concept: a function that returns JSX.
Step 2: Add Some Interactivity
Static text is boring. Let's add a button that does something when clicked:
function App() {
// This function runs when the button is clicked
const handleClick = () => {
alert('Hello from React!')
}
return (
<div>
<h1>Hello, World!</h1>
<p>Welcome to my first React app!</p>
<button onClick={handleClick}>
Click Me!
</button>
</div>
)
}
export default AppClick the button in your browser. You should see an alert! Notice how we:
- Created a function
handleClickinside our component - Attached it to the button using
onClick={handleClick} - Used curly braces to pass the JavaScript function to JSX
Step 3: Add State
Now let's make it more interesting by adding state - data that can change over time:
import { useState } from 'react'
function App() {
// Create a piece of state called 'name'
const [name, setName] = useState('World')
const handleClick = () => {
setName('React Developer')
}
return (
<div>
<h1>Hello, {name}!</h1>
<p>Welcome to my first React app!</p>
<button onClick={handleClick}>
Change Greeting
</button>
</div>
)
}
export default AppNow when you click the button, the greeting changes! Let's understand what's happening:
useState('World')creates state with initial value "World"- It returns an array with two elements: the current value
nameand a function to update itsetName - We display
namein the heading using curly braces - When the button is clicked,
setNameupdates the state - React automatically re-renders the component with the new value
💡 Tip: Edit the code above and click "Run" to see your changes
Adding Styles to Your Component
Let's make our app look better! There are several ways to style React components. Let's explore the most common approaches:
Method 1: Inline Styles
You can add styles directly to elements using the style attribute. In React, styles are JavaScript objects:
function App() {
const [name, setName] = useState('World')
const containerStyle = {
textAlign: 'center',
padding: '2rem',
fontFamily: 'Arial, sans-serif'
}
const headingStyle = {
color: '#6366f1',
fontSize: '2.5rem',
marginBottom: '1rem'
}
const buttonStyle = {
backgroundColor: '#6366f1',
color: 'white',
padding: '0.75rem 1.5rem',
border: 'none',
borderRadius: '0.5rem',
fontSize: '1rem',
cursor: 'pointer'
}
return (
<div style={containerStyle}>
<h1 style={headingStyle}>Hello, {name}!</h1>
<p>Welcome to my first React app!</p>
<button style={buttonStyle} onClick={() => setName('React Developer')}>
Change Greeting
</button>
</div>
)
}Notice that CSS properties use camelCase (backgroundColor instead of background-color) and values are strings.
Method 2: CSS Files
For better organization, you can use separate CSS files. Update src/App.css:
.app-container {
text-align: center;
padding: 2rem;
font-family: Arial, sans-serif;
}
.app-heading {
color: #6366f1;
font-size: 2.5rem;
margin-bottom: 1rem;
}
.app-button {
background-color: #6366f1;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 0.5rem;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s;
}
.app-button:hover {
background-color: #4f46e5;
}Then use these classes in your component:
import { useState } from 'react'
import './App.css'
function App() {
const [name, setName] = useState('World')
return (
<div className="app-container">
<h1 className="app-heading">Hello, {name}!</h1>
<p>Welcome to my first React app!</p>
<button
className="app-button"
onClick={() => setName('React Developer')}
>
Change Greeting
</button>
</div>
)
}
export default App⚠️ className vs class
Remember to use className in JSX, not class. This is because class is a reserved keyword in JavaScript (used for creating classes).
Building Something Real: Personal Card
Let's build something more practical - a personal information card with multiple pieces of state:
import { useState } from 'react'
import './App.css'
function App() {
const [isVisible, setIsVisible] = useState(true)
const [darkMode, setDarkMode] = useState(false)
return (
<div className={`app-container ${darkMode ? 'dark-mode' : ''}`}>
<div className="controls">
<button onClick={() => setIsVisible(!isVisible)}>
{isVisible ? 'Hide' : 'Show'} Card
</button>
<button onClick={() => setDarkMode(!darkMode)}>
Toggle {darkMode ? 'Light' : 'Dark'} Mode
</button>
</div>
{isVisible && (
<div className="profile-card">
<img
src="https://via.placeholder.com/150"
alt="Profile"
className="profile-image"
/>
<h2>John Doe</h2>
<p className="title">React Developer</p>
<p className="description">
Building awesome web applications with React!
</p>
<div className="stats">
<div className="stat">
<strong>50+</strong>
<span>Projects</span>
</div>
<div className="stat">
<strong>1000+</strong>
<span>Commits</span>
</div>
<div className="stat">
<strong>2024</strong>
<span>Started</span>
</div>
</div>
</div>
)}
</div>
)
}
export default AppAnd add these styles to src/App.css:
.app-container {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
background-color: #f3f4f6;
transition: background-color 0.3s;
}
.app-container.dark-mode {
background-color: #1f2937;
color: white;
}
.controls {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
}
.controls button {
padding: 0.5rem 1rem;
background-color: #6366f1;
color: white;
border: none;
border-radius: 0.5rem;
cursor: pointer;
font-size: 0.875rem;
transition: background-color 0.3s;
}
.controls button:hover {
background-color: #4f46e5;
}
.profile-card {
background: white;
border-radius: 1rem;
padding: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
max-width: 400px;
width: 100%;
animation: slideIn 0.3s ease-out;
}
.dark-mode .profile-card {
background: #374151;
}
.profile-image {
width: 150px;
height: 150px;
border-radius: 50%;
object-fit: cover;
margin-bottom: 1rem;
}
.title {
color: #6366f1;
font-weight: 600;
margin: 0.5rem 0;
}
.description {
color: #6b7280;
margin: 1rem 0;
}
.dark-mode .description {
color: #9ca3af;
}
.stats {
display: flex;
justify-content: space-around;
margin-top: 1.5rem;
padding-top: 1.5rem;
border-top: 1px solid #e5e7eb;
}
.dark-mode .stats {
border-top-color: #4b5563;
}
.stat {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.stat strong {
font-size: 1.5rem;
color: #6366f1;
}
.stat span {
font-size: 0.875rem;
color: #6b7280;
}
.dark-mode .stat span {
color: #9ca3af;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}This example demonstrates several React concepts working together:
- Multiple state variables:
isVisibleanddarkMode - Conditional rendering: Using
{isVisible && ...}to show/hide the card - Dynamic className: Using template literals to apply classes conditionally
- Event handlers: Toggling state on button clicks
- CSS transitions: Smooth visual effects
💡 Tip: Edit the code above and click "Run" to see your changes
Common Beginner Mistakes
Let's look at some common mistakes beginners make and how to avoid them:
1. Forgetting to Import useState
// ❌ Wrong - Will cause error
function App() {
const [count, setCount] = useState(0) // useState is not defined!
// ...
}// ✅ Correct
import { useState } from 'react'
function App() {
const [count, setCount] = useState(0)
// ...
}2. Using class Instead of className
// ❌ Wrong
<div class="container">Hello</div>// ✅ Correct
<div className="container">Hello</div>3. Modifying State Directly
// ❌ Wrong - Never modify state directly!
const [count, setCount] = useState(0)
count = count + 1 // This won't work and causes bugs// ✅ Correct - Always use the setter function
const [count, setCount] = useState(0)
setCount(count + 1)4. Forgetting to Return JSX
// ❌ Wrong - No return statement
function App() {
const [count, setCount] = useState(0)
<div>
<h1>Count: {count}</h1>
</div>
}// ✅ Correct
function App() {
const [count, setCount] = useState(0)
return (
<div>
<h1>Count: {count}</h1>
</div>
)
}5. Multiple Root Elements Without a Wrapper
// ❌ Wrong - Adjacent JSX elements must be wrapped
return (
<h1>Title</h1>
<p>Paragraph</p>
)// ✅ Correct - Wrapped in a div or fragment
return (
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
)
// ✅ Or use fragments
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
)Using React Developer Tools
React has special browser extensions that make debugging much easier. If you haven't already, install React Developer Tools:
- Chrome: Search "React Developer Tools" in Chrome Web Store
- Firefox: Search "React DevTools" in Firefox Add-ons
Once installed:
- Open your React app in the browser
- Open browser DevTools (F12)
- Click the "Components" tab (it appears alongside Console, Network, etc.)
You'll be able to:
- See the component tree
- Inspect props and state of each component
- Modify state values to test different scenarios
- See which components re-render and why
🔧 Pro Developer Habit
Get in the habit of using React DevTools. It's like X-ray vision for your React apps - you can see exactly what's happening inside your components!
Key Takeaways
- React apps start with
index.html, loadmain.jsx, which renders yourAppcomponent - Components are JavaScript functions that return JSX
- Component names must start with a capital letter
- JSX looks like HTML but has important differences (className, onClick, etc.)
- Use
useStateto add state to your components - State updates trigger re-renders automatically
- Never modify state directly - always use the setter function
- Use curly braces
{}to embed JavaScript in JSX - Style components with inline styles, CSS files, or CSS-in-JS
- React Developer Tools are essential for debugging
- Multiple root elements must be wrapped in a parent or fragment
What's Next?
Congratulations! You've built your first React app from scratch and learned the fundamentals of how React works. You understand components, JSX, state, and event handling - that's a solid foundation!
In the next lesson, we'll dive deeper into JSX - the special syntax that makes React so powerful. You'll learn all the details about how JSX works, how it differs from HTML, and how to write it like a pro. Get ready to level up your React skills! 🚀
💪 Practice Challenge
Before moving on, try customizing the profile card we built. Change the colors, add more stats, or create a different type of card entirely. The best way to learn React is by building things!