React: Building Modern User Interfaces

React is a JavaScript library for building user interfaces. Created by Facebook, it's the most popular choice for modern web development, used by companies like Netflix, Airbnb, and Instagram.

Why React?

React has become the go-to choice for frontend development because:

  • Component-based: Build encapsulated, reusable UI pieces
  • Declarative: Describe what you want, React handles the DOM updates
  • Virtual DOM: Efficient updates for better performance
  • Huge ecosystem: Thousands of libraries, tools, and resources
  • Strong job market: Most in-demand frontend skill

React vs Vanilla JavaScript

// Vanilla JavaScript - imperative
const button = document.createElement('button');
button.textContent = 'Clicks: 0';
let count = 0;
button.addEventListener('click', () => {
  count++;
  button.textContent = 'Clicks: ' + count;
});
document.body.appendChild(button);

// React - declarative
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Clicks: {count}
    </button>
  );
}

Getting Started

The easiest way to start a new React project is with Vite or Create React App:

# Using Vite (recommended)
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev

# Using Create React App
npx create-react-app my-app
cd my-app
npm start

Project Structure

my-app/
├── src/
│   ├── App.jsx        # Main component
│   ├── main.jsx       # Entry point
│   ├── index.css      # Global styles
│   └── components/    # Your components
├── public/            # Static assets
├── package.json       # Dependencies
└── vite.config.js     # Build configuration

Components

Components are the building blocks of React applications. They're JavaScript functions that return JSX (HTML-like syntax in JavaScript).

Function Components

// Simple component
function Welcome() {
  return <h1>Hello, World!</h1>;
}

// Component with JSX expressions
function Greeting() {
  const name = "Alice";
  const date = new Date().toLocaleDateString();

  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Today is {date}</p>
    </div>
  );
}

// Using the component
function App() {
  return (
    <div>
      <Welcome />
      <Greeting />
    </div>
  );
}

JSX Rules

  • Single root element: Wrap multiple elements in a <div> or <>...</>
  • Close all tags: Including self-closing tags like <img />
  • camelCase attributes: className instead of class, onClick instead of onclick
  • JavaScript in curly braces: {expression}

Props & State

Props pass data from parent to child. State manages data that changes over time.

Props (Properties)

// Parent passes props
function App() {
  return <UserCard name="Alice" role="Developer" />;
}

// Child receives props
function UserCard({ name, role }) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>{role}</p>
    </div>
  );
}

// Props with default values
function Button({ text = "Click me", variant = "primary" }) {
  return <button className={variant}>{text}</button>;
}

State with useState

import { useState } from 'react';

function Counter() {
  // Declare state variable with initial value
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(0)}>
        Reset
      </button>
    </div>
  );
}

State with Objects

function Form() {
  const [user, setUser] = useState({
    name: '',
    email: ''
  });

  const handleChange = (e) => {
    setUser({
      ...user,  // Keep existing values
      [e.target.name]: e.target.value  // Update changed field
    });
  };

  return (
    <form>
      <input
        name="name"
        value={user.name}
        onChange={handleChange}
        placeholder="Name"
      />
      <input
        name="email"
        value={user.email}
        onChange={handleChange}
        placeholder="Email"
      />
    </form>
  );
}

Hooks

Hooks let you use state and other React features in function components.

useEffect - Side Effects

import { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Runs after component mounts
    fetch('https://api.example.com/data')
      .then(res => res.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, []); // Empty array = run once on mount

  if (loading) return <p>Loading...</p>;
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

Common Hooks

Hook Purpose
useState Manage component state
useEffect Side effects (data fetching, subscriptions)
useContext Access context values
useRef Reference DOM elements or persist values
useMemo Memoize expensive calculations
useCallback Memoize functions

Event Handling

function EventExamples() {
  const handleClick = () => {
    alert('Button clicked!');
  };

  const handleSubmit = (e) => {
    e.preventDefault();  // Prevent form submission
    console.log('Form submitted');
  };

  const handleInput = (e) => {
    console.log('Input value:', e.target.value);
  };

  return (
    <div>
      <button onClick={handleClick}>Click Me</button>

      <form onSubmit={handleSubmit}>
        <input onChange={handleInput} />
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

Conditional Rendering

function Dashboard({ isLoggedIn, isAdmin }) {
  // Using ternary operator
  return (
    <div>
      {isLoggedIn ? (
        <h1>Welcome back!</h1>
      ) : (
        <h1>Please log in</h1>
      )}

      {/* Using && for conditional display */}
      {isAdmin && <button>Admin Panel</button>}
    </div>
  );
}

// Early return pattern
function UserProfile({ user }) {
  if (!user) {
    return <p>No user found</p>;
  }

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

Lists & Keys

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React', done: false },
    { id: 2, text: 'Build a project', done: false },
    { id: 3, text: 'Deploy to production', done: false }
  ]);

  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    ));
  };

  return (
    <ul>
      {todos.map(todo => (
        <li
          key={todo.id}  // Always use unique keys!
          onClick={() => toggleTodo(todo.id)}
          style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
        >
          {todo.text}
        </li>
      ))}
    </ul>
  );
}
Why Keys? Keys help React identify which items changed, were added, or removed. Always use stable, unique identifiers (like IDs), not array indices.

Next Steps

You've learned the React fundamentals! Continue your journey:

  • React Router: Add navigation and multiple pages
  • State management: Redux, Zustand, or Context API for complex state
  • Styling: CSS Modules, Tailwind CSS, or styled-components
  • Next.js: Full-stack React framework with SSR
  • Testing: Jest and React Testing Library

Related Guides