Home / Notebooks / Frontend Development
Frontend Development
beginner

React Fundamentals

Getting started with React - learn the core concepts and build your first interactive web applications

April 21, 2026
Updated regularly

React Fundamentals

React is a JavaScript library for building user interfaces. This guide will take you from zero to building your first React applications.

Why React?

The Problem: Traditional JavaScript requires manual DOM manipulation, making complex UIs difficult to maintain.

The Solution: React uses a component-based approach where you describe what the UI should look like, and React handles the updates efficiently.

Benefits:

  • Write less code for complex UIs
  • Reusable components
  • Fast performance with Virtual DOM
  • Large ecosystem and community
  • Used by Facebook, Instagram, Netflix, Airbnb
  • Your First React App

    Setup

    The easiest way to start is with Vite:

    # Create new React project
    npm create vite@latest my-first-app -- --template react
    
    # Navigate to project
    cd my-first-app
    
    # Install dependencies
    npm install
    
    # Start development server
    npm run dev
    

    Open your browser to http://localhost:5173

    Hello World

    Replace src/App.jsx with:

    function App() {
      return <h1>Hello, React!</h1>;
    }
    
    export default App;
    

    Congratulations! You just created your first React component.

    Understanding JSX

    JSX looks like HTML but it's actually JavaScript.

    // This JSX...
    const element = <h1>Hello!</h1>;
    
    // ...gets transformed to...
    const element = React.createElement('h1', null, 'Hello!');
    

    JSX Basics

    // Text content
    <h1>Hello World</h1>
    
    // Using JavaScript expressions
    const name = "Sarah";
    <h1>Hello {name}!</h1>
    
    // Attributes
    <img src="photo.jpg" alt="My photo" />
    
    // Children
    <div>
      <h1>Title</h1>
      <p>Paragraph</p>
    </div>
    
    // Fragments (no extra DOM element)
    <>
      <h1>Title</h1>
      <p>Paragraph</p>
    </>
    

    Important Rules

    // ❌ Wrong: class (JavaScript keyword)
    <div class="container">
    
    // ✅ Correct: className
    <div className="container">
    
    // ❌ Wrong: Multiple root elements
    return (
      <h1>Title</h1>
      <p>Text</p>
    )
    
    // ✅ Correct: Single root or Fragment
    return (
      <>
        <h1>Title</h1>
        <p>Text</p>
      </>
    )
    
    // ❌ Wrong: Unclosed tag
    <img src="photo.jpg">
    
    // ✅ Correct: Self-closing
    <img src="photo.jpg" />
    

    Components

    Components are the building blocks of React apps.

    Function Components

    // Simple component
    function Welcome() {
      return <h1>Welcome to my app!</h1>;
    }
    
    // Arrow function component
    const Welcome = () => {
      return <h1>Welcome to my app!</h1>;
    };
    
    // Using the component
    function App() {
      return (
        <div>
          <Welcome />
          <Welcome />
          <Welcome />
        </div>
      );
    }
    

    Component with Logic

    function Greeting() {
      const hour = new Date().getHours();
      const timeOfDay = hour < 12 ? "morning" : hour < 18 ? "afternoon" : "evening";
      
      return <h1>Good {timeOfDay}!</h1>;
    }
    

    Props - Passing Data

    Props let you pass data from parent to child components.

    // Parent component
    function App() {
      return (
        <div>
          <UserCard name="Alice" age={25} />
          <UserCard name="Bob" age={30} />
          <UserCard name="Charlie" age={35} />
        </div>
      );
    }
    
    // Child component
    function UserCard(props) {
      return (
        <div className="card">
          <h2>{props.name}</h2>
          <p>Age: {props.age}</p>
        </div>
      );
    }
    
    // Destructured props (cleaner)
    function UserCard({ name, age }) {
      return (
        <div className="card">
          <h2>{name}</h2>
          <p>Age: {age}</p>
        </div>
      );
    }
    

    Props Are Read-Only

    function UserCard({ name }) {
      // ❌ Never modify props
      name = "Modified"; // This is wrong!
      
      // ✅ Props should be treated as read-only
      return <h2>{name}</h2>;
    }
    

    Children Prop

    function Card({ children, title }) {
      return (
        <div className="card">
          <h3>{title}</h3>
          <div>{children}</div>
        </div>
      );
    }
    
    // Usage
    <Card title="My Card">
      <p>This is the content</p>
      <button>Click me</button>
    </Card>
    

    State - Interactive Components

    State lets components remember information and change over time.

    import { useState } from 'react';
    
    function Counter() {
      // Declare state variable
      const [count, setCount] = useState(0);
      
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );
    }
    

    How useState Works

    const [value, setValue] = useState(initialValue);
    //      ↑        ↑              ↑
    //   current   updater     initial value
    //   value     function
    

    Multiple State Variables

    function Form() {
      const [name, setName] = useState('');
      const [email, setEmail] = useState('');
      const [age, setAge] = useState(0);
      
      return (
        <div>
          <input 
            value={name} 
            onChange={(e) => setName(e.target.value)}
            placeholder="Name"
          />
          <input 
            value={email} 
            onChange={(e) => setEmail(e.target.value)}
            placeholder="Email"
          />
          <input 
            type="number"
            value={age} 
            onChange={(e) => setAge(e.target.value)}
            placeholder="Age"
          />
        </div>
      );
    }
    

    State with Objects

    function UserForm() {
      const [user, setUser] = useState({
        name: '',
        email: '',
        age: 0
      });
      
      const updateField = (field, value) => {
        setUser({
          ...user,           // Keep other fields
          [field]: value     // Update this field
        });
      };
      
      return (
        <div>
          <input 
            value={user.name}
            onChange={(e) => updateField('name', e.target.value)}
          />
          <input 
            value={user.email}
            onChange={(e) => updateField('email', e.target.value)}
          />
        </div>
      );
    }
    

    Handling Events

    React events work similarly to DOM events but with camelCase naming.

    function Button() {
      const handleClick = () => {
        alert('Button clicked!');
      };
      
      return <button onClick={handleClick}>Click me</button>;
    }
    
    // Inline function
    <button onClick={() => alert('Clicked!')}>Click me</button>
    
    // With event parameter
    function Form() {
      const handleSubmit = (e) => {
        e.preventDefault(); // Prevent page reload
        console.log('Form submitted');
      };
      
      return <form onSubmit={handleSubmit}>...</form>;
    }
    
    // Common events
    <button onClick={() => {}}>Click</button>
    <input onChange={(e) => console.log(e.target.value)} />
    <form onSubmit={(e) => e.preventDefault()}>...</form>
    <div onMouseEnter={() => {}} onMouseLeave={() => {}}>Hover me</div>
    

    Conditional Rendering

    Show different UI based on conditions.

    // Using if statement
    function Greeting({ isLoggedIn }) {
      if (isLoggedIn) {
        return <h1>Welcome back!</h1>;
      }
      return <h1>Please sign in</h1>;
    }
    
    // Using ternary operator
    function Greeting({ isLoggedIn }) {
      return (
        <div>
          {isLoggedIn ? (
            <h1>Welcome back!</h1>
          ) : (
            <h1>Please sign in</h1>
          )}
        </div>
      );
    }
    
    // Using && for conditional content
    function Notifications({ count }) {
      return (
        <div>
          <h1>Inbox</h1>
          {count > 0 && (
            <p>You have {count} unread messages</p>
          )}
        </div>
      );
    }
    

    Lists and Keys

    Render multiple items from an array.

    function TodoList() {
      const todos = [
        { id: 1, text: 'Learn React' },
        { id: 2, text: 'Build an app' },
        { id: 3, text: 'Deploy it' }
      ];
      
      return (
        <ul>
          {todos.map((todo) => (
            <li key={todo.id}>{todo.text}</li>
          ))}
        </ul>
      );
    }
    

    Why Keys Matter: Keys help React identify which items have changed, been added, or removed.

    // ✅ Good: Stable ID
    {items.map(item => <li key={item.id}>{item.name}</li>)}
    
    // ⚠️ Only if no stable ID and list never reorders
    {items.map((item, index) => <li key={index}>{item}</li>)}
    
    // ❌ Never use random values
    {items.map(item => <li key={Math.random()}>{item}</li>)}
    

    Building Real Apps

    Example 1: Counter with Reset

    import { useState } from 'react';
    
    function Counter() {
      const [count, setCount] = useState(0);
      
      return (
        <div style={{ textAlign: 'center', marginTop: '50px' }}>
          <h1>Counter: {count}</h1>
          <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
            <button onClick={() => setCount(count - 1)}>-</button>
            <button onClick={() => setCount(0)}>Reset</button>
            <button onClick={() => setCount(count + 1)}>+</button>
          </div>
        </div>
      );
    }
    
    export default Counter;
    

    Example 2: Todo App

    import { useState } from 'react';
    
    function TodoApp() {
      const [todos, setTodos] = useState([]);
      const [input, setInput] = useState('');
      
      const addTodo = () => {
        if (input.trim()) {
          setTodos([...todos, { id: Date.now(), text: input, done: false }]);
          setInput('');
        }
      };
      
      const toggleTodo = (id) => {
        setTodos(todos.map(todo =>
          todo.id === id ? { ...todo, done: !todo.done } : todo
        ));
      };
      
      const deleteTodo = (id) => {
        setTodos(todos.filter(todo => todo.id !== id));
      };
      
      return (
        <div style={{ maxWidth: '500px', margin: '50px auto' }}>
          <h1>My Todo List</h1>
          
          <div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
            <input
              type="text"
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyPress={(e) => e.key === 'Enter' && addTodo()}
              placeholder="What needs to be done?"
              style={{ flex: 1, padding: '10px' }}
            />
            <button onClick={addTodo} style={{ padding: '10px 20px' }}>
              Add
            </button>
          </div>
          
          <ul style={{ listStyle: 'none', padding: 0 }}>
            {todos.map(todo => (
              <li
                key={todo.id}
                style={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: '10px',
                  padding: '10px',
                  background: '#f5f5f5',
                  marginBottom: '10px',
                  borderRadius: '5px'
                }}
              >
                <input
                  type="checkbox"
                  checked={todo.done}
                  onChange={() => toggleTodo(todo.id)}
                />
                <span
                  style={{
                    flex: 1,
                    textDecoration: todo.done ? 'line-through' : 'none'
                  }}
                >
                  {todo.text}
                </span>
                <button onClick={() => deleteTodo(todo.id)}>Delete</button>
              </li>
            ))}
          </ul>
          
          {todos.length === 0 && (
            <p style={{ textAlign: 'center', color: '#999' }}>
              No todos yet. Add one above!
            </p>
          )}
        </div>
      );
    }
    
    export default TodoApp;
    

    Example 3: Temperature Converter

    import { useState } from 'react';
    
    function TemperatureConverter() {
      const [celsius, setCelsius] = useState('');
      const [fahrenheit, setFahrenheit] = useState('');
      
      const handleCelsiusChange = (value) => {
        setCelsius(value);
        if (value === '') {
          setFahrenheit('');
        } else {
          const f = (parseFloat(value) * 9/5) + 32;
          setFahrenheit(f.toFixed(2));
        }
      };
      
      const handleFahrenheitChange = (value) => {
        setFahrenheit(value);
        if (value === '') {
          setCelsius('');
        } else {
          const c = (parseFloat(value) - 32) * 5/9;
          setCelsius(c.toFixed(2));
        }
      };
      
      return (
        <div style={{ maxWidth: '400px', margin: '50px auto', textAlign: 'center' }}>
          <h1>Temperature Converter</h1>
          
          <div style={{ marginBottom: '20px' }}>
            <label style={{ display: 'block', marginBottom: '5px' }}>
              Celsius
            </label>
            <input
              type="number"
              value={celsius}
              onChange={(e) => handleCelsiusChange(e.target.value)}
              style={{ padding: '10px', width: '200px' }}
            />
          </div>
          
          <div>
            <label style={{ display: 'block', marginBottom: '5px' }}>
              Fahrenheit
            </label>
            <input
              type="number"
              value={fahrenheit}
              onChange={(e) => handleFahrenheitChange(e.target.value)}
              style={{ padding: '10px', width: '200px' }}
            />
          </div>
        </div>
      );
    }
    
    export default TemperatureConverter;
    

    Example 4: Simple Form

    import { useState } from 'react';
    
    function ContactForm() {
      const [formData, setFormData] = useState({
        name: '',
        email: '',
        message: ''
      });
      const [submitted, setSubmitted] = useState(false);
      
      const handleChange = (e) => {
        setFormData({
          ...formData,
          [e.target.name]: e.target.value
        });
      };
      
      const handleSubmit = (e) => {
        e.preventDefault();
        console.log('Form data:', formData);
        setSubmitted(true);
        
        // Reset form after 3 seconds
        setTimeout(() => {
          setFormData({ name: '', email: '', message: '' });
          setSubmitted(false);
        }, 3000);
      };
      
      if (submitted) {
        return (
          <div style={{ maxWidth: '500px', margin: '50px auto', textAlign: 'center' }}>
            <h2>✓ Thank you!</h2>
            <p>Your message has been sent.</p>
          </div>
        );
      }
      
      return (
        <div style={{ maxWidth: '500px', margin: '50px auto' }}>
          <h1>Contact Us</h1>
          <form onSubmit={handleSubmit}>
            <div style={{ marginBottom: '15px' }}>
              <label style={{ display: 'block', marginBottom: '5px' }}>
                Name
              </label>
              <input
                type="text"
                name="name"
                value={formData.name}
                onChange={handleChange}
                required
                style={{ width: '100%', padding: '10px' }}
              />
            </div>
            
            <div style={{ marginBottom: '15px' }}>
              <label style={{ display: 'block', marginBottom: '5px' }}>
                Email
              </label>
              <input
                type="email"
                name="email"
                value={formData.email}
                onChange={handleChange}
                required
                style={{ width: '100%', padding: '10px' }}
              />
            </div>
            
            <div style={{ marginBottom: '15px' }}>
              <label style={{ display: 'block', marginBottom: '5px' }}>
                Message
              </label>
              <textarea
                name="message"
                value={formData.message}
                onChange={handleChange}
                required
                rows={5}
                style={{ width: '100%', padding: '10px' }}
              />
            </div>
            
            <button
              type="submit"
              style={{
                padding: '10px 30px',
                background: '#007bff',
                color: 'white',
                border: 'none',
                borderRadius: '5px',
                cursor: 'pointer'
              }}
            >
              Send Message
            </button>
          </form>
        </div>
      );
    }
    
    export default ContactForm;
    

    Component Organization

    As your app grows, organize components into separate files:

    src/
    ├── components/
    │   ├── Header.jsx
    │   ├── Footer.jsx
    │   ├── TodoItem.jsx
    │   └── TodoList.jsx
    ├── App.jsx
    └── main.jsx
    
    TodoItem.jsx:
    function TodoItem({ todo, onToggle, onDelete }) {
      return (
        <li>
          <input
            type="checkbox"
            checked={todo.done}
            onChange={() => onToggle(todo.id)}
          />
          <span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
            {todo.text}
          </span>
          <button onClick={() => onDelete(todo.id)}>Delete</button>
        </li>
      );
    }
    
    export default TodoItem;
    
    TodoList.jsx:
    import TodoItem from './TodoItem';
    
    function TodoList({ todos, onToggle, onDelete }) {
      return (
        <ul>
          {todos.map(todo => (
            <TodoItem
              key={todo.id}
              todo={todo}
              onToggle={onToggle}
              onDelete={onDelete}
            />
          ))}
        </ul>
      );
    }
    
    export default TodoList;
    

    Styling Your App

    Inline Styles

    <div style={{ color: 'blue', fontSize: '20px' }}>
      Styled text
    </div>
    

    CSS Files

    Button.css:
    .btn {
      padding: 10px 20px;
      border: none;
      border-radius: 5px;
      cursor: pointer;
    }
    
    .btn-primary {
      background: #007bff;
      color: white;
    }
    
    Button.jsx:
    import './Button.css';
    
    function Button({ children, variant = 'primary' }) {
      return (
        <button className={`btn btn-${variant}`}>
          {children}
        </button>
      );
    }
    

    Common Mistakes

    1. Forgetting to Return

    // ❌ Wrong
    function MyComponent() {
      <div>Hello</div>
    }
    
    // ✅ Correct
    function MyComponent() {
      return <div>Hello</div>;
    }
    

    2. Not Using Key in Lists

    // ❌ Wrong
    {items.map(item => <li>{item}</li>)}
    
    // ✅ Correct
    {items.map(item => <li key={item.id}>{item}</li>)}
    

    3. Modifying State Directly

    // ❌ Wrong
    count = count + 1;
    
    // ✅ Correct
    setCount(count + 1);
    

    4. Not Handling Events Correctly

    // ❌ Wrong (calls function immediately)
    <button onClick={handleClick()}>
    
    // ✅ Correct
    <button onClick={handleClick}>
    <button onClick={() => handleClick()}>
    

    Next Steps

    Now that you understand React fundamentals:

  • Practice - Build small projects (calculator, weather app, quiz app)
  • Learn useEffect - For side effects and data fetching
  • Try React Router - For multi-page applications
  • Explore State Management - Context API or libraries like Zustand
  • Build a Full Project - Combine everything you've learned
  • Quick Reference

    Essential Hooks

    // State
    const [value, setValue] = useState(initialValue);
    
    // Side effects (coming in next lessons)
    useEffect(() => {
      // Run side effects
    }, [dependencies]);
    

    Common Patterns

    // Mapping arrays
    {items.map(item => <Item key={item.id} {...item} />)}
    
    // Conditional rendering
    {condition && <Component />}
    {condition ? <ComponentA /> : <ComponentB />}
    
    // Handling forms
    <input value={value} onChange={(e) => setValue(e.target.value)} />
    
    // Event handling
    <button onClick={() => doSomething()}>Click</button>
    

    Resources

    Official Docs:

  • https://react.dev - Official React documentation
  • https://react.dev/learn - Interactive React tutorial
  • Practice:

  • Build a calculator
  • Create a weather app
  • Make a quiz app
  • Build a note-taking app
  • Community:

  • React Discord server
  • Reddit r/reactjs
  • Stack Overflow
  • Key Takeaways

  • Components are the building blocks
  • Props pass data down
  • State makes components interactive
  • JSX looks like HTML but is JavaScript
  • Keys help React identify list items
  • Events use camelCase naming
  • Don't modify state directly - use the setter function
  • Ready to build something amazing? Start with a simple project and gradually add features. The best way to learn React is by building!

    Topics

    ReactJavaScriptFrontendWeb DevelopmentUI

    Found This Helpful?

    If you have questions or suggestions for improving these notes, I'd love to hear from you.