Skip to content

React Fundamentals

React is a library for building user interfaces. It lets you build UI components that are declarative, efficient, and flexible.

JSX is a syntax extension for JavaScript. It looks like HTML, but it comes with the full power of JavaScript.

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

In our Task Manager project, we use JSX to define the structure of our components.

Components are the building blocks of any React application. They let you split the UI into independent, reusable pieces.

We use modern Functional Components with TypeScript.

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

Props (short for properties) are how we pass data from a parent component to a child component. They are read-only.

interface WelcomeProps {
name: string;
isAdmin?: boolean; // Optional prop
}
function Welcome({ name, isAdmin }: WelcomeProps) {
return (
<div>
<h1>Hello, {name}</h1>
{isAdmin && <span className="badge">Admin</span>}
</div>
);
}
// Usage
<Welcome name="Alice" isAdmin={true} />;

Handling events in React is similar to handling events on DOM elements.

function Button() {
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log("Button clicked!", event);
};
return <button onClick={handleClick}>Click me</button>;
}

In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application.

function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
// Using Logical && Operator
function Mailbox({ unreadMessages }: { unreadMessages: string[] }) {
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && (
<h2>You have {unreadMessages.length} unread messages.</h2>
)}
</div>
);
}

When rendering a list of items, you should provide a unique key prop for each item.

function TaskList({ tasks }: { tasks: Task[] }) {
return (
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
);
}

Forms are how users interact with your application.

function CreateTaskForm() {
const [title, setTitle] = useState("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); // Prevent page reload
console.log("Submitting:", title);
};
return (
<form onSubmit={handleSubmit}>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Task Title"
/>
<button type="submit">Create</button>
</form>
);
}

When fetching data, it’s important to show the user that something is happening.

function TaskList() {
const [isLoading, setIsLoading] = useState(true);
const [tasks, setTasks] = useState([]);
useEffect(() => {
fetch("/api/tasks")
.then((res) => res.json())
.then((data) => {
setTasks(data);
setIsLoading(false);
});
}, []);
if (isLoading) {
return <div>Loading tasks...</div>;
}
return (
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
);
}

Hooks let you use state and other React features without writing a class.

useState is a Hook that lets you add React state to function components.

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>
);
}

useEffect lets you perform side effects in function components (like data fetching, subscriptions, or manually changing the DOM).

import { useEffect } from "react";
function PageTitle() {
useEffect(() => {
document.title = "Task Manager";
}, []); // Empty dependency array means this runs once on mount
return <div>Check the tab title!</div>;
}

In our Task Manager (tm) project, we often extract logic into custom hooks. For example, useTasksQuery encapsulates the logic for fetching tasks.

// Example concept from our project
export const useTasksQuery = () => {
// ... logic to fetch tasks
};

This keeps our components clean and focused on the UI.