The Road To Dev currently has AI-generated placeholder content. This is temporary - content is being actively developed.

content

React Fundamentals

Building modern user interfaces with React components and JSX

React Fundamentals

React is a powerful JavaScript library for building user interfaces. This lesson covers the essential concepts that form the foundation of React development: components, JSX, props, and state.

Learning Objectives

By the end of this lesson, you will understand:

  • What React is and why it's popular
  • How to create and use React components
  • JSX syntax and how it differs from HTML
  • How to pass data between components with props
  • How to manage component state with useState

What is React?

React is a JavaScript library developed by Facebook for building user interfaces, particularly web applications. Key characteristics:

Component-Based Architecture

  • Build encapsulated components that manage their own state
  • Compose components to create complex UIs
  • Reusable and maintainable code

Declarative Programming

  • Describe what the UI should look like for any given state
  • React handles the how (DOM manipulation)
  • More predictable and easier to debug

Virtual DOM

  • React maintains a virtual representation of the DOM
  • Efficiently updates only what has changed
  • Better performance than direct DOM manipulation

Your First React Component

Function Components

Modern React uses function components with hooks:

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

Arrow Function Components

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

Rendering Components

import React from 'react';
import ReactDOM from 'react-dom/client';
function App() {
return (
<div>
<Welcome />
<Welcome />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

JSX (JavaScript XML)

JSX is a syntax extension that allows you to write HTML-like code in JavaScript.

JSX vs HTML Differences

// JSX uses className instead of class
<div className="container">
<h1>Hello React</h1>
</div>
// JSX uses camelCase for attributes
<input
type="text"
onChange={handleChange}
maxLength={100}
/>
// Self-closing tags must be closed
<img src="photo.jpg" alt="Description" />
<br />
<hr />

Embedding JavaScript in JSX

function Greeting() {
const name = "Alice";
const isLoggedIn = true;
return (
<div>
<h1>Hello, {name}!</h1>
{isLoggedIn && <p>Welcome back!</p>}
<p>You have {2 + 3} unread messages</p>
</div>
);
}

Conditional Rendering

function UserStatus({ isLoggedIn, username }) {
return (
<div>
{isLoggedIn ? (
<h1>Welcome back, {username}!</h1>
) : (
<h1>Please sign in</h1>
)}
</div>
);
}

Rendering Lists

function TodoList() {
const todos = [
{ id: 1, text: "Learn React", completed: false },
{ id: 2, text: "Build a project", completed: false },
{ id: 3, text: "Deploy to production", completed: true }
];
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text} {todo.completed && '✓'}
</li>
))}
</ul>
);
}

Props (Properties)

Props allow you to pass data from parent to child components.

Basic Props

function Greeting({ name, age }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>You are {age} years old</p>
</div>
);
}
function App() {
return (
<div>
<Greeting name="Alice" age={30} />
<Greeting name="Bob" age={25} />
</div>
);
}

Props with Different Data Types

function UserCard({
name,
age,
isOnline,
hobbies,
address
}) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>Age: {age}</p>
<p>Status: {isOnline ? 'Online' : 'Offline'}</p>
<h3>Hobbies:</h3>
<ul>
{hobbies.map((hobby, index) => (
<li key={index}>{hobby}</li>
))}
</ul>
<p>Location: {address.city}, {address.country}</p>
</div>
);
}
// Usage
<UserCard
name="Alice"
age={28}
isOnline={true}
hobbies={["reading", "hiking", "coding"]}
address={{ city: "New York", country: "USA" }}
/>

Default Props

function Button({ text = "Click me", type = "button" }) {
return <button type={type}>{text}</button>;
}
// These are equivalent
<Button />
<Button text="Click me" type="button" />

Children Prop

function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
function App() {
return (
<Card>
<h2>Card Title</h2>
<p>Card content goes here</p>
<button>Action</button>
</Card>
);
}

State with useState Hook

State allows components to store and manage data that can change over time.

Basic useState

import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Current count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<button onClick={() => setCount(0)}>
Reset
</button>
</div>
);
}

State with Objects

function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateName = (newName) => {
setUser(prevUser => ({
...prevUser,
name: newName
}));
};
return (
<div>
<input
type="text"
placeholder="Name"
value={user.name}
onChange={(e) => updateName(e.target.value)}
/>
<input
type="email"
placeholder="Email"
value={user.email}
onChange={(e) => setUser(prev => ({
...prev,
email: e.target.value
}))}
/>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
}

State with Arrays

function TodoApp() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
if (inputValue.trim()) {
setTodos(prevTodos => [
...prevTodos,
{
id: Date.now(),
text: inputValue,
completed: false
}
]);
setInputValue('');
}
};
const toggleTodo = (id) => {
setTodos(prevTodos =>
prevTodos.map(todo =>
todo.id === id
? { ...todo, completed: !todo.completed }
: todo
)
);
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}

Event Handling

React handles events using SyntheticEvents, which wrap native events.

Common Event Handlers

function EventExamples() {
const [message, setMessage] = useState('');
const handleClick = () => {
alert('Button clicked!');
};
const handleMouseOver = (e) => {
console.log('Mouse over:', e.target);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted with:', message);
};
const handleKeyDown = (e) => {
if (e.key === 'Enter') {
console.log('Enter key pressed');
}
};
return (
<form onSubmit={handleSubmit}>
<button
onClick={handleClick}
onMouseOver={handleMouseOver}
>
Click me
</button>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Type something..."
/>
<button type="submit">Submit</button>
</form>
);
}

Component Composition

Building complex UIs by combining simpler components.

Composition Example

function Header() {
return (
<header>
<h1>My App</h1>
<nav>
<a href="#home">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
</header>
);
}
function Sidebar() {
return (
<aside>
<h3>Quick Links</h3>
<ul>
<li><a href="#link1">Link 1</a></li>
<li><a href="#link2">Link 2</a></li>
</ul>
</aside>
);
}
function MainContent({ children }) {
return (
<main>
{children}
</main>
);
}
function App() {
return (
<div className="app">
<Header />
<div className="content">
<Sidebar />
<MainContent>
<h2>Welcome to My App</h2>
<p>This is the main content area.</p>
</MainContent>
</div>
</div>
);
}

Best Practices

Component Organization

// ✅ Good: Clear, descriptive names
function UserProfileCard({ user }) {
return (
<div className="user-profile-card">
<img src={user.avatar} alt={`${user.name}'s avatar`} />
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
// ❌ Avoid: Vague names
function Card({ data }) {
return <div>{data.name}</div>;
}

State Management

// ✅ Good: Keep state close to where it's used
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
// Component logic here
}
// ❌ Avoid: Too much state in one component
function App() {
const [searchTerm, setSearchTerm] = useState('');
const [userProfile, setUserProfile] = useState({});
const [cartItems, setCartItems] = useState([]);
const [notifications, setNotifications] = useState([]);
// ... too much state!
}

Props Validation (TypeScript)

interface UserProps {
name: string;
age: number;
email?: string; // Optional
}
function User({ name, age, email }: UserProps) {
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
{email && <p>Email: {email}</p>}
</div>
);
}

Common Patterns

Controlled Components

function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submitting:', formData);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Your name"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Your email"
/>
<textarea
name="message"
value={formData.message}
onChange={handleChange}
placeholder="Your message"
/>
<button type="submit">Send</button>
</form>
);
}

Lifting State Up

function Parent() {
const [sharedState, setSharedState] = useState('');
return (
<div>
<ChildA
value={sharedState}
onChange={setSharedState}
/>
<ChildB value={sharedState} />
</div>
);
}
function ChildA({ value, onChange }) {
return (
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
);
}
function ChildB({ value }) {
return <p>Value from sibling: {value}</p>;
}

Debugging React

React Developer Tools

  • Install React DevTools browser extension
  • Inspect component hierarchy
  • View props and state
  • Track component updates

Common Debugging Techniques

function DebuggingExample() {
const [count, setCount] = useState(0);
// Log to see when component renders
console.log('Component rendered with count:', count);
// Log state changes
const handleIncrement = () => {
console.log('Before increment:', count);
setCount(prev => {
const newCount = prev + 1;
console.log('After increment:', newCount);
return newCount;
});
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>+1</button>
</div>
);
}

Summary

React fundamentals provide the foundation for building modern web applications:

  • Components: Reusable pieces of UI
  • JSX: HTML-like syntax in JavaScript
  • Props: Data passed between components
  • State: Component data that can change
  • Events: Handling user interactions

Key principles:

  • Components should be focused and reusable
  • Props flow down, events flow up
  • State should be kept as local as possible
  • Always use keys when rendering lists

Next Steps

Now that you understand React fundamentals, you're ready to explore:

  • React Hooks (useEffect, useContext, custom hooks)
  • Component lifecycle and side effects
  • Styling React components
  • React Router for navigation
  • State management with Context API or external libraries

Practice building small applications to reinforce these concepts before moving on to more advanced topics!

Lesson Complete!

Great job! You've finished this lesson. Ready to continue?