Skip to main content
React 3 mins read Devs2.org

React for Beginners - A Complete Step-by-Step Guide to Building Modern Web Apps

Learn React from scratch with this comprehensive beginner guide. Discover components, JSX, hooks, state management, and how to build your first React app step by step.

#React #JavaScript #Frontend #Web Development #Tutorial #Beginner Guide #Components #Hooks

If HTML is the skeleton and CSS is the skin of a website, then React is the brain — it thinks, reacts, and dynamically updates everything around it. React has become the most popular frontend library in the world, powering millions of websites including Facebook, Instagram, Netflix, Airbnb, and thousands more.

react-for-beginners

Whether you’re looking to land your first frontend developer job, build your own startup’s product, or simply understand what all the hype is about, this guide will walk you through everything you need to know to get started with React — from zero to building your first interactive application.

What is React?

React is a free, open-source JavaScript library for building user interfaces. Developed and maintained by Meta (formerly Facebook), React allows developers to create large web applications that can update and render efficiently in response to data changes.

Unlike traditional websites that reload the entire page when content changes, React uses a component-based architecture. This means you build your UI as a collection of small, reusable pieces called components, each managing its own state and rendering independently.

Why Choose React?

React dominates the frontend landscape for several compelling reasons:

  1. Component-Based Architecture: Build encapsulated components that manage their own state, then compose them to create complex UIs
  2. Virtual DOM: React’s virtual DOM optimizes rendering performance by only updating changed elements, not the entire page
  3. Declarative Syntax: Describe what your UI should look like for any given state, and React handles the DOM updates automatically
  4. Learn Once, Write Anywhere: Build web apps with React.js, or mobile apps with React Native using the same component patterns
  5. Massive Ecosystem: Thousands of libraries, tools, and resources available to accelerate development
  6. Strong Job Market: React developers are among the most in-demand frontend engineers globally
  7. Backed by Meta: Continuous development, extensive documentation, and a thriving community

Prerequisites: What You Need Before Starting

Before diving into React, make sure you’re comfortable with these JavaScript concepts:

  • Variables (let, const)
  • Functions (including arrow functions)
  • Arrays and Objects (creation, iteration, methods)
  • ES6+ Features:
    • Arrow functions: const greet = () => {}
    • Template literals: const msg = `Hello ${name}`
    • Destructuring: const { name } = person
    • Spread operator: [...arr1, ...arr2]
    • Modules: import / export
  • Array Methods: map(), filter(), reduce(), find()
  • DOM Manipulation basics
  • Promises and Async/Await for API calls

If any of these feel unfamiliar, we recommend reviewing our JavaScript Basics for Beginners guide first.

Setting Up Your First React Project

The easiest way to start with React is using Create React App, a tool that sets up a complete development environment for you.

Step 1: Install Node.js

First, ensure you have Node.js installed. Download it from nodejs.org and install the LTS version. Verify the installation:

node -v   # Should show v18.x or higher
npm -v    # Should show v9.x or higher

Step 2: Create a New React App

Open your terminal and run:

npx create-react-app my-first-react-app

This command creates a new folder called my-first-react-app with everything pre-configured.

Step 3: Start the Development Server

cd my-first-react-app
npm start

Your browser will automatically open to http://localhost:3000, showing your running React application!

Project Structure

After creating the app, your project will look like this:

my-first-react-app/
├── node_modules/       # Dependencies
├── public/             # Static files
│   └── index.html      # HTML entry point
├── src/                # Source code
│   ├── App.css         # App styles
│   ├── App.js          # Main App component
│   ├── App.test.js     # Tests
│   ├── index.css       # Global styles
│   ├── index.js        # Entry point
│   └── logo.svg        # Assets
├── package.json        # Dependencies and scripts
└── README.md           # Documentation

Understanding Components

At the heart of React is the component — a self-contained, reusable piece of UI. Think of components as custom HTML elements that you define yourself.

There are two types of components in React:

Functional components are JavaScript functions that return JSX. They are the modern, preferred way to write React components:

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

That’s it! This function is a complete React component. When React encounters <Welcome /> in your code, it runs the function and renders whatever it returns.

Class Components (Legacy)

Class components use ES6 classes and are the older approach. While still supported, functional components with hooks are now the standard:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, World!</h1>;
  }
}

We’ll focus on functional components throughout this guide.

JSX: Writing HTML Inside JavaScript

JSX (JavaScript XML) is a syntax extension that lets you write HTML-like markup directly inside JavaScript. It looks like HTML, but it’s actually JavaScript under the hood.

Basic JSX Examples

// Simple element
const element = <h1>Welcome to React!</h1>;

// With attributes
const greeting = <p className="intro">Hello, React!</p>;

// Self-closing tags
const image = <img src="logo.png" alt="Logo" />;

// Multiple elements wrapped in a fragment
const list = (
  <>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </>
);

Key JSX Rules

  1. Return a single root element: Wrap multiple elements in a fragment <>...</> or a <div>
  2. Use className instead of class: Since class is a reserved word in JavaScript
  3. Close all tags: Unlike HTML, JSX requires all tags to be closed (e.g., <img />)
  4. Use camelCase for attributes: onClick instead of onclick, tabIndex instead of tabindex
  5. JavaScript expressions go in curly braces: {variable}, {expression()}, {condition && value}

Mixing JavaScript with JSX

One of React’s most powerful features is embedding JavaScript expressions directly in JSX using curly braces {}:

function UserCard({ name, age, email }) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
      <p>Status: {age >= 18 ? 'Adult' : 'Minor'}</p>
    </div>
  );
}

Rendering Lists

Use the .map() method to render lists of items:

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}>{todo}</li>
      ))}
    </ul>
  );
}

// Usage
const tasks = ['Learn React', 'Build a project', 'Deploy to production'];
<TodoList todos={tasks} />

Important: Always provide a unique key prop when rendering lists. Keys help React identify which items have changed, been added, or removed.

Props: Passing Data Between Components

Props (short for properties) are how you pass data from parent components to child components. They are read-only — a component cannot modify its own props.

Passing Props

// Parent component
function App() {
  return (
    <div>
      <Greeting name="Alice" />
      <Greeting name="Bob" />
      <Greeting name="Charlie" />
    </div>
  );
}

// Child component
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

Props Can Be Any Type

function UserProfile({ user }) {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>Email: {user.email}</p>
      <p>Posts: {user.postCount}</p>
      <button onClick={() => console.log('Followed!')}>Follow</button>
    </div>
  );
}

// Usage
const userData = {
  name: 'Dev',
  email: 'dev@example.com',
  postCount: 42
};

<UserProfile user={userData} />

Default Props

You can set default values for props:

function Button({ label = 'Click Me', onClick = () => {} }) {
  return <button onClick={onClick}>{label}</button>;
}

State: Managing Dynamic Data

While props flow down from parent to child, state is data managed within a component. When state changes, React automatically re-renders the component with the updated data.

Using the useState Hook

The useState hook is the primary way to add state to functional components:

import { useState } from 'react';

function Counter() {
  // Declare a state variable called 'count'
  // Initial value is 0
  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

  1. useState(initialValue) returns an array with two elements
  2. The first element is the current state value
  3. The second element is a function to update the state
  4. When you call the setter function, React re-renders the component

State with Different Data Types

function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [isEditing, setIsEditing] = useState(false);

  const addTodo = () => {
    if (inputValue.trim()) {
      setTodos([...todos, inputValue]);
      setInputValue('');
    }
  };

  const removeTodo = (index) => {
    setTodos(todos.filter((_, i) => i !== index));
  };

  return (
    <div>
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Add a todo..."
      />
      <button onClick={addTodo}>Add</button>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>
            {todo}
            <button onClick={() => removeTodo(index)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Important: Never Modify State Directly

// ❌ WRONG — Direct mutation
count = count + 1;
todos.push(newTodo);

// ✅ CORRECT — Use the setter function
setCount(count + 1);
setTodos([...todos, newTodo]);

Direct mutations won’t trigger a re-render. Always use the setter function provided by useState.

Common React Hooks

Hooks are functions that let you “hook into” React features from functional components. Here are the most essential ones:

useEffect — Side Effects

The useEffect hook lets you perform side effects in your components, such as fetching data, subscribing to events, or manually changing the DOM.

import { useState, useEffect } from 'react';

function WeatherDisplay({ city }) {
  const [weather, setWeather] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Fetch weather data when city changes
    setLoading(true);
    fetch(`https://api.weather.com/${city}`)
      .then(response => response.json())
      .then(data => {
        setWeather(data);
        setLoading(false);
      });
  }, [city]); // Re-run when 'city' changes

  if (loading) return <p>Loading...</p>;
  return <p>{city}: {weather.temperature}°C</p>;
}

The dependency array [city] tells React when to re-run the effect. An empty array [] means run once on mount.

useContext — Sharing Data Globally

The useContext hook lets you share values between components without passing props through every level:

import { createContext, useContext, useState } from 'react';

// Create context
const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <div className={`app ${theme}`}>
        <Header />
        <MainContent />
      </div>
    </ThemeContext.Provider>
  );
}

function Header() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <header>
      <h1>My App</h1>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </header>
  );
}

useReducer — Complex State Logic

For complex state logic with multiple sub-values, useReducer is often cleaner than useState:

import { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return { ...state, todos: [...state.todos, action.payload] };
    case 'REMOVE_TODO':
      return {
        ...state,
        todos: state.todos.filter((_, i) => i !== action.payload)
      };
    case 'TOGGLE_TODO':
      return {
        ...state,
        todos: state.todos.map((todo, i) =>
          i === action.payload ? { ...todo, done: !todo.done } : todo
        )
      };
    default:
      return state;
  }
}

function TodoApp() {
  const [state, dispatch] = useReducer(reducer, { todos: [] });

  return (
    <div>
      {state.todos.map((todo, index) => (
        <div key={index}>
          <span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
            {todo.text}
          </span>
          <button onClick={() => dispatch({ type: 'TOGGLE_TODO', payload: index })}>
            Toggle
          </button>
          <button onClick={() => dispatch({ type: 'REMOVE_TODO', payload: index })}>
            Remove
          </button>
        </div>
      ))}
    </div>
  );
}

Building a Complete React Application

Let’s put everything together by building a Task Manager application — a practical example that demonstrates components, props, state, hooks, and event handling.

TaskManager Component

import { useState } from 'react';
import './TaskManager.css';

function TaskManager() {
  const [tasks, setTasks] = useState([
    { id: 1, text: 'Learn React fundamentals', completed: false },
    { id: 2, text: 'Build a task manager app', completed: false },
    { id: 3, text: 'Deploy to production', completed: false },
  ]);
  const [newTask, setNewTask] = useState('');
  const [filter, setFilter] = useState('all');

  const addTask = () => {
    if (newTask.trim() === '') return;
    const task = {
      id: Date.now(),
      text: newTask,
      completed: false,
    };
    setTasks([...tasks, task]);
    setNewTask('');
  };

  const toggleTask = (id) => {
    setTasks(tasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    ));
  };

  const deleteTask = (id) => {
    setTasks(tasks.filter(task => task.id !== id));
  };

  const filteredTasks = tasks.filter(task => {
    if (filter === 'active') return !task.completed;
    if (filter === 'completed') return task.completed;
    return true;
  });

  const completedCount = tasks.filter(t => t.completed).length;

  return (
    <div className="task-manager">
      <h1>📋 Task Manager</h1>

      {/* Add Task Form */}
      <div className="add-task">
        <input
          type="text"
          value={newTask}
          onChange={(e) => setNewTask(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && addTask()}
          placeholder="Add a new task..."
        />
        <button onClick={addTask}>Add</button>
      </div>

      {/* Filter Buttons */}
      <div className="filters">
        <button
          className={filter === 'all' ? 'active' : ''}
          onClick={() => setFilter('all')}
        >
          All ({tasks.length})
        </button>
        <button
          className={filter === 'active' ? 'active' : ''}
          onClick={() => setFilter('active')}
        >
          Active ({tasks.length - completedCount})
        </button>
        <button
          className={filter === 'completed' ? 'active' : ''}
          onClick={() => setFilter('completed')}
        >
          Completed ({completedCount})
        </button>
      </div>

      {/* Task List */}
      <ul className="task-list">
        {filteredTasks.map(task => (
          <li key={task.id} className={`task ${task.completed ? 'completed' : ''}`}>
            <input
              type="checkbox"
              checked={task.completed}
              onChange={() => toggleTask(task.id)}
            />
            <span className="task-text">{task.text}</span>
            <button
              className="delete-btn"
              onClick={() => deleteTask(task.id)}
            >

            </button>
          </li>
        ))}
      </ul>

      {filteredTasks.length === 0 && (
        <p className="empty-message">No tasks to show!</p>
      )}
    </div>
  );
}

export default TaskManager;

Styling the Task Manager

/* TaskManager.css */
.task-manager {
  max-width: 600px;
  margin: 2rem auto;
  padding: 2rem;
  font-family: system-ui, sans-serif;
}

.add-task {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.add-task input {
  flex: 1;
  padding: 0.75rem;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 1rem;
}

.add-task button {
  padding: 0.75rem 1.5rem;
  background: #6366f1;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
}

.filters {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.filters button {
  padding: 0.5rem 1rem;
  border: 2px solid #e0e0e0;
  background: white;
  border-radius: 6px;
  cursor: pointer;
}

.filters button.active {
  border-color: #6366f1;
  background: #eef2ff;
  color: #6366f1;
  font-weight: 600;
}

.task-list {
  list-style: none;
  padding: 0;
}

.task {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem;
  border-bottom: 1px solid #f0f0f0;
}

.task.completed .task-text {
  text-decoration: line-through;
  color: #999;
}

.delete-btn {
  margin-left: auto;
  background: none;
  border: none;
  color: #ef4444;
  cursor: pointer;
  font-size: 1.2rem;
}

React Router: Navigating Between Pages

For multi-page applications, React Router is the standard solution:

npm install react-router-dom
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
        <Link to="/contact">Contact</Link>
      </nav>

      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/about" element={<AboutPage />} />
        <Route path="/contact" element={<ContactPage />} />
      </Routes>
    </BrowserRouter>
  );
}

Best Practices for React Beginners

As you grow with React, keep these best practices in mind:

1. Keep Components Small and Focused

Each component should do one thing well. If a component grows too large, split it into smaller sub-components:

// ❌ Too many responsibilities
function Dashboard() {
  // header logic + sidebar logic + chart logic + table logic
}

// ✅ Split into focused components
function Dashboard() {
  return (
    <>
      <DashboardHeader />
      <Sidebar />
      <ChartSection />
      <DataTable />
    </>
  );
}

2. Use Meaningful Component Names

Name components based on what they represent, not how they look:

// ❌ Bad names
function Box1() {
function Wrapper2() {

// ✅ Good names
function ProductCard() {
function NavigationMenu() {

3. Lift State Up When Needed

When multiple components need shared state, lift it to their closest common parent:

// Both SearchBar and Results need access to query
function SearchContainer() {
  const [query, setQuery] = useState('');
  return (
    <>
      <SearchBar query={query} onChange={setQuery} />
      <Results query={query} />
    </>
  );
}

4. Avoid Inline Function Definitions in JSX

Creating functions inline causes unnecessary re-renders:

// ❌ Creates new function on every render
<button onClick={() => handleClick(id)}>Delete</button>

// ✅ Define outside or use useCallback
<button onClick={() => handleClick(id)}>Delete</button>
// Better: define handler outside component or memoize with useCallback

5. Use Conditional Rendering Wisely

// ✅ Good patterns
{isLoading && <Spinner />}
{items.length > 0 ? <ItemList items={items} /> : <EmptyState />}
{isLoggedIn && <UserProfile />}

Next Steps After Learning the Basics

Once you’re comfortable with the fundamentals covered in this guide, here’s where to go next:

  1. Build Real Projects: Create a portfolio site, a weather app, or a recipe finder
  2. Learn About APIs: Practice fetching data from REST APIs and GraphQL endpoints
  3. Explore State Management: Learn Redux Toolkit or Zustand for larger applications
  4. Study React Patterns: Compound components, render props, custom hooks
  5. Try Next.js: Learn server-side rendering and static site generation
  6. Write Tests: Explore Jest and React Testing Library
  7. Contribute to Open Source: Find beginner-friendly React projects on GitHub

Frequently Asked Questions

Is React difficult to learn?

React has a moderate learning curve. The core concepts (components, props, state) are straightforward, but mastering the ecosystem (routing, state management, testing, deployment) takes time. The key is to start simple and gradually add complexity as you become more comfortable.

Do I need to learn all the hooks?

Start with useState and useEffect — these two cover most use cases. As you encounter more complex scenarios, gradually learn useContext, useReducer, useCallback, and useMemo. Don’t try to memorize all hooks at once; learn them as you need them.

Can I use React without JSX?

Technically yes, using React.createElement(), but it’s extremely verbose and hard to read. JSX is so deeply integrated into the React ecosystem that writing React without it is rarely done in practice.

How does React compare to vanilla JavaScript?

With vanilla JavaScript, you manually manipulate the DOM whenever data changes. React abstracts this away — you update the state, and React efficiently updates the DOM for you. This makes React faster to develop with and less error-prone for complex applications.

What’s the difference between React and ReactDOM?

React is the library for building UI components. ReactDOM is the package that lets React render those components in the browser. For web projects, you need both. For mobile apps, you’d use React Native instead of ReactDOM.

Conclusion

React is an incredibly powerful tool for building modern, interactive web applications. By understanding components, JSX, props, state, and hooks, you now have the foundation to build anything from simple interactive widgets to complex single-page applications.

Remember: the best way to learn React is by building things. Start with small projects, experiment with different features, and don’t be afraid to break things — that’s how you learn!

Happy coding! 🚀

Recently Used Tools