React Complete Guide for Beginners

React Complete Guide for Beginners

React is a powerful JavaScript library for building user interfaces, particularly web applications. Created by Facebook, React has become one of the most popular frontend frameworks in the world.

What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you compose complex UIs from small and isolated pieces of code called "components."

Key Features

  • Component-Based: Build encapsulated components that manage their own state
  • Virtual DOM: Efficient updates and rendering
  • One-Way Data Flow: Predictable data flow makes debugging easier
  • JSX: JavaScript syntax extension that looks like HTML
  • Rich Ecosystem: Thousands of packages and tools available

Setting Up React

Using Create React App

The easiest way to get started with React is using Create React App:

npx create-react-app my-app
cd my-app
npm start

For faster development and better performance:

npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev

Components

Functional Components

function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>;
}

// Using arrow function
const Welcome = (props) => {
  return <h1>Hello, {props.name}!</h1>;
};

Class Components

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

JSX

JSX is a syntax extension that lets you write HTML-like code in JavaScript:

const element = <h1>Hello, world!</h1>;

// JSX with expressions
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

// JSX with attributes
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;

State and Props

Props

Props are read-only data passed down from parent components:

function UserCard(props) {
  return (
    <div className="user-card">
      <h2>{props.name}</h2>
      <p>{props.email}</p>
      <span>Age: {props.age}</span>
    </div>
  );
}

// Usage
<UserCard name="John Doe" email="john@example.com" age={25} />

State with Hooks

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

React Hooks

useState Hook

import { useState } from 'react';

function Form() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ name, email });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Name"
      />
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

useEffect Hook

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
  }, []); // Empty dependency array means this runs once

  if (loading) return <div>Loading...</div>;

  return <div>{JSON.stringify(data)}</div>;
}

Event Handling

function Button() {
  const handleClick = (e) => {
    e.preventDefault();
    console.log('Button clicked!');
  };

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

// With parameters
function TodoItem({ todo, onDelete }) {
  return (
    <div>
      <span>{todo.text}</span>
      <button onClick={() => onDelete(todo.id)}>
        Delete
      </button>
    </div>
  );
}

Conditional Rendering

function UserGreeting({ isLoggedIn, user }) {
  if (isLoggedIn) {
    return <h1>Welcome back, {user.name}!</h1>;
  }
  return <h1>Please sign up.</h1>;
}

// Using ternary operator
function LoginButton({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <button>Logout</button>
      ) : (
        <button>Login</button>
      )}
    </div>
  );
}

// Using logical AND
function Mailbox({ unreadMessages }) {
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 && (
        <h2>You have {unreadMessages.length} unread messages.</h2>
      )}
    </div>
  );
}

Lists and Keys

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

// More complex example
function ProductList({ products }) {
  return (
    <div className="product-grid">
      {products.map(product => (
        <div key={product.id} className="product-card">
          <h3>{product.name}</h3>
          <p>${product.price}</p>
          <button>Add to Cart</button>
        </div>
      ))}
    </div>
  );
}

Forms

import { useState } from 'react';

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const handleChange = (e) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };

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

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="Your Name"
        required
      />
      <input
        type="email"
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Your Email"
        required
      />
      <textarea
        name="message"
        value={formData.message}
        onChange={handleChange}
        placeholder="Your Message"
        rows="5"
        required
      />
      <button type="submit">Send Message</button>
    </form>
  );
}

Best Practices

1. Component Structure

// Good: Single responsibility
function UserProfile({ user }) {
  return (
    <div className="user-profile">
      <UserAvatar user={user} />
      <UserInfo user={user} />
      <UserActions user={user} />
    </div>
  );
}

// Bad: Too many responsibilities
function UserProfile({ user }) {
  // Avatar, info, actions, settings, etc. all in one component
}

2. Props Destructuring

// Good
function UserCard({ name, email, avatar }) {
  return (
    <div>
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

// Also good for many props
function UserCard(props) {
  const { name, email, avatar, ...otherProps } = props;
  return (
    <div {...otherProps}>
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

3. Custom Hooks

// Custom hook for API calls
function useApi(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        setError(error);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}

// Usage
function UserList() {
  const { data: users, loading, error } = useApi('/api/users');

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Next Steps

  1. Learn React Router: For client-side routing
  2. State Management: Redux, Zustand, or Context API
  3. Testing: Jest and React Testing Library
  4. Performance: React.memo, useMemo, useCallback
  5. Advanced Patterns: Higher-Order Components, Render Props

Resources

Happy coding with React!

/* */