React: Introduction and Project Setup
React is a JavaScript library for building user interfaces, maintained by Meta and first released in 2013. It sits at the heart of the modern JavaScript ecosystem — powering everything from single-page apps to entire tech stacks at companies like Netflix, Airbnb, and Instagram. This tutorial walks you through what React solves, how to scaffold a project with Vite, and how to write your first components.
What Problems React Solves
Building UIs with plain JavaScript works, but it creates specific headaches as applications grow. Every time your data changes, you have to find the right DOM nodes and update them manually. That process is slow, error-prone, and difficult to reason about.
React addresses this through a few core ideas:
- Virtual DOM — React keeps an in-memory copy of the DOM. When your data changes, it rebuilds the virtual representation, compares it against the previous version (this is called diffing), and surgically updates only the nodes that actually changed in the real DOM.
- Components — UI is broken into small, self-contained pieces. Each component encapsulates its own logic and rendering, making it easy to reason about isolated pieces of an interface.
- Unidirectional data flow — Data flows down from parent to child via props. When a child needs to communicate upward, it calls a function passed down as a prop. This constraint makes data flow predictable and bugs easier to trace.
These ideas work together. Components keep your code organised. The virtual DOM keeps rendering fast. Unidirectional data flow keeps your application easy to follow.
Scaffolding with Vite
Vite is the recommended way to create a React project. Its name is French for “fast” — and it earns that label. During development, Vite serves your files as native ES modules. No bundling step, no waiting forWebpack to rebuild everything. Changes appear the moment you save.
Install and scaffold a project:
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev
```jsx
Vite will print the address of your local dev server — typically `http://localhost:5173`. Open that in your browser and you'll see the starter app.
Other package managers work equally well:
```bash
# Yarn
yarn create vite my-react-app --template react
# pnpm
pnpm create vite my-react-app --template react
```jsx
To add TypeScript from the start, swap the template to `react-ts`. The setup is otherwise identical.
## Project Structure
After scaffolding, your project looks like this:
```jsx
my-react-app/
├── index.html # HTML entry point
├── package.json # Dependencies and scripts
├── vite.config.js # Vite configuration
├── src/
│ ├── main.jsx # React app bootstrap
│ ├── App.jsx # Root component
│ ├── App.css # App-level styles
│ ├── index.css # Global styles
│ └── assets/ # Images and static assets
└── public/ # Static assets served as-is
```jsx
The most important file is **`index.html`**, which contains a single `<div id="root"></div>`. Every React element your application produces renders inside that div.
**`src/main.jsx`** is the bootstrap point:
```jsx
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>,
)
```jsx
`React.StrictMode` activates additional checks in development that help you spot problems early — such as unsafe lifecycle methods or missing `key` props in lists.
**`src/App.jsx`** is the root component. This is where you start composing your interface. In a new project it renders some boilerplate; you'll replace it with your own UI.
## JSX: HTML in JavaScript
JSX lets you write HTML-like markup directly inside JavaScript. It is not required — `React.createElement()` works without it — but JSX is the idiomatic way to describe React UIs.
JSX expressions must follow a few rules:
- **Return a single root element.** Wrap siblings in a `<div>` or a fragment `<>...</>`.
- **Use `className` instead of `class`.** `class` is reserved in JavaScript.
- **Use camelCase for attributes.** `tab-index` becomes `tabIndex`, `onclick` becomes `onClick`.
- **Embed JavaScript with curly braces.** Any JS expression goes inside `{}`.
- **Close self-closing tags.** `<img />` not `<img>`.
```jsx
// Wrong — two siblings without a wrapper
return (<h1>Title</h1><p>Text</p>);
// Correct — wrapped in a fragment
return (
<>
<h1>Title</h1>
<p>Text</p>
</>
);
// Embedding a JavaScript expression
const name = "World";
return <h1>Hello, {name}!</h1>;
```jsx
Under the hood, JSX compiles to `React.createElement()` calls. The result is a plain JavaScript object — not HTML.
## Your First Component
A React component is a function that accepts an input (called **props**) and returns JSX. Component names must start with a capital letter — React treats `<MyComponent />` as a component and `<mycomponent />` as an HTML element.
```jsx
function Greeting({ name }) {
return <p>Welcome, {name}!</p>;
}
function App() {
return (
<div>
<Greeting name="Sarah" />
<Greeting name="Mike" />
</div>
);
}
// Renders: "Welcome, Sarah!" and "Welcome, Mike!"
```jsx
### Props
Props pass data from a parent to a child. They are read-only — a component should never modify the props it receives.
```jsx
function UserCard({ username, role }) {
return (
<div className="user-card">
<h2>{username}</h2>
<p>Role: {role}</p>
</div>
);
}
// Usage:
<UserCard username="alice" role="admin" />
// Renders a card showing "alice" with role "admin"
```jsx
### State with `useState`
Props flow down. When data needs to change inside a component, you use **state** — data that lives in the component and, when it changes, triggers a re-render. The `useState` hook manages local component state.
```jsx
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<span>Count: {count}</span>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
// Updates the UI immediately on every click
```jsx
Calling `setCount` tells React that the state has changed. React then re-renders the component with the new value, updates the DOM, and the user sees the updated count.
### Conditional Rendering
Components can return different JSX depending on state or props.
```jsx
function LoginStatus({ isLoggedIn, username }) {
if (isLoggedIn) {
return <p>Hello, {username}!</p>;
}
return <p>Please log in.</p>;
}
function App() {
return (
<>
<LoginStatus isLoggedIn={true} username="Jordan" />
<LoginStatus isLoggedIn={false} />
</>
);
}
// Renders: "Hello, Jordan!" and "Please log in."
```jsx
### Rendering Lists
Use `Array.prototype.map()` to render a list of elements. Every item in a rendered list needs a `key` prop — a unique identifier that helps React track items across re-renders.
```jsx
function FruitList({ fruits }) {
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
}
function App() {
const fruits = ['Apple', 'Banana', 'Cherry'];
return <FruitList fruits={fruits} />;
}
// Renders: Apple, Banana, Cherry as an unordered list
```jsx
Use the array index as a key only when the list is static and will not be reordered. For dynamic lists where items can be added, removed, or reordered, use a stable unique ID instead.
## Running and Building
```bash
# Start the dev server with hot module replacement
npm run dev
# Build for production (outputs to dist/)
npm run build
# Preview the production build locally
npm run preview
```jsx
Press `Ctrl+C` in the terminal to stop the dev server.
## Common Mistakes to Avoid
- **Capitalization** — `<MyComponent />` is a component; `<mycomponent />` is an HTML element. This is one of the most common beginner errors.
- **`className` not `class`** — Writing `class="container"` in JSX silently fails. Always use `className`.
- **Missing `key` in lists** — Maps without a `key` prop produce console warnings and cause rendering bugs when the list changes.
- **Mutating state directly** — Always use the setter function: `setCount(count + 1)`, not `count++`. Direct mutations do not trigger a re-render.
- **Self-closing tags** — `<img />` requires the trailing slash. `<img>` is invalid JSX.
## Next Steps
With a working project and the component basics in place, you're ready to move deeper. The next topics worth exploring are how React handles side effects with the `useEffect` hook, how to share state across components with React Context, and how routing works in single-page applications.
---
## See Also
- [JavaScript Closures](/guides/javascript-closures/) — closures are used throughout React for event handlers, callbacks, and maintaining state in scope
- [The Event Loop](/guides/javascript-event-loop/) — understanding how JavaScript handles asynchronous operations pairs well with React's state model
- [ES Modules](/guides/javascript-modules-esm/) — React projects use ES module imports and exports to organize components across files