When I build a recent activity dashboard, I do not write one huge file for every card, filter, button, and ticket row. I split the screen into smaller pieces that each handle one clear job. That makes the app easier to read, test, update, and reuse.
Those smaller pieces are React components. Once you understand them, building pages in React starts to feel far more organized.
This guide explains what a React component is, how functional components work, and how to use them in a practical support-ticket dashboard.
What Is a React Component?
A React component is a reusable JavaScript function that returns part of the user interface.
In React, the interface you see in the browser comes from many components working together. A page might include a navigation component, a dashboard component, a ticket-list component, and a button component.
Each component returns JSX. JSX is syntax that looks similar to HTML but runs inside JavaScript. React uses JSX to describe what should appear on the page.
Here is a small example:
function WelcomeMessage() {
return <h1>Welcome to the support dashboard</h1>;
}
export default WelcomeMessage;
This component is named WelcomeMessage. It returns an <h1> element, so React renders that heading in the browser.
Component names must begin with an uppercase letter. React uses that capital letter to distinguish your components from built-in HTML elements such as <div>, <button>, and <section>.
For example:
function TicketCard() {
return <article>Open support ticket</article>;
}
function App() {
return <TicketCard />;
}
TicketCard is a component, while article is a standard HTML element. The App component renders TicketCard by using it like a custom JSX tag.
If you are setting up a new project, this guide on how to create your first React application can help you get the local environment ready.
Why React Components Matter
Components help you break a large interface into focused, manageable parts. I use them constantly in dashboards because dashboard screens often contain repeated patterns.
For example, a support dashboard may contain:
- A header with the current user and notifications
- A summary area with ticket counts
- A ticket list
- A reusable ticket row
- A filter panel
- An empty-state message
Without components, all that code may live in one App.jsx file. That approach works for a tiny demo, but it quickly becomes difficult to maintain.
With components, each part gets a clear purpose:
function Dashboard() {
return (
<main>
<DashboardHeader />
<TicketSummary />
<TicketList />
</main>
);
}
This code reads almost like a page outline. Dashboard acts as a parent component and combines several child components.
This organization also supports React component reuse. You can render the same ticket card across an open-ticket page, a customer profile, and a dashboard without duplicating its markup.
Create Your First Functional Component
Modern React applications usually use functional components. A functional component is a JavaScript function that returns JSX.
Here is a simple ticket component:
function TicketStatus() {
return <p>Status: Open</p>;
}
export default TicketStatus;
You can render it inside another component:
import TicketStatus from "./TicketStatus";
function App() {
return (
<div>
<h1>Support Center</h1>
<TicketStatus />
</div>
);
}
export default App;
I executed the above example code and added the screenshot below.

The App component imports and renders TicketStatus. React then combines both pieces into one screen.
A component should focus on one responsibility. TicketStatus displays ticket status. It should not also fetch every ticket, manage navigation, and format user settings. Keeping components small helps you understand and change them faster.
Return JSX From a Component
Every React component returns JSX, null, or another valid React value. In most cases, you return JSX that describes the UI.
Here is a ticket card:
function TicketCard() {
return (
<article className="ticket-card">
<h2>Login issue</h2>
<p>Customer cannot access the account portal.</p>
<span>Priority: High</span>
</article>
);
}
The parentheses make multiline JSX easier to read. The className attribute works like HTML’s class attribute, but JSX uses className because class is a JavaScript keyword.
React components must return one parent element. If you do not want an extra <div>, use a React fragment:
function TicketCard() {
return (
<>
<h2>Login issue</h2>
<p>Customer cannot access the account portal.</p>
</>
);
}
The empty <>...</> syntax groups the JSX without adding an element to the page.
Pass Data With Props
A component becomes useful when it can display different data. You pass that data through props.
Props are values that a parent component sends to a child component. Think of them like function arguments.
Here is a reusable TicketCard component:
function TicketCard({ title, priority, customer }) {
return (
<article className="ticket-card">
<h2>{title}</h2>
<p>Customer: {customer}</p>
<span>Priority: {priority}</span>
</article>
);
}
The curly braces let you use JavaScript values inside JSX. This component receives title, priority, and customer as props.
Now you can reuse the component with different information:
function TicketList() {
return (
<section>
<TicketCard
title="Login issue"
customer="Asha Patel"
priority="High"
/>
<TicketCard
title="Invoice not received"
customer="Rahul Mehta"
priority="Medium"
/>
</section>
);
}
Each TicketCard uses the same layout but shows different values. That is the real advantage of component-based development.
For a deeper explanation of passing data, see this guide on props in React.
Store Changing Data With State
Props come from a parent component. State belongs to the component itself and stores data that can change over time.
For example, a ticket dashboard may let users hide or show resolved tickets. The visibility setting needs state.
React provides useState for this job. useState is a React Hook for storing and updating component data.
A React Hook is a special React function that lets functional components use features such as state and lifecycle behavior.
import { useState } from "react";
function TicketPanel() {
const [showResolved, setShowResolved] = useState(false);
return (
<section>
<button onClick={() => setShowResolved(!showResolved)}>
{showResolved ? "Hide resolved tickets" : "Show resolved tickets"}
</button>
<p>
Resolved tickets are {showResolved ? "visible" : "hidden"}.
</p>
</section>
);
}
I executed the above example code and added the screenshot below.

showResolved stores the current value. setShowResolved updates that value. The initial value is false.
When the user clicks the button, React updates the state and renders the component again with the latest value. Learn more about handling clicks and other user actions in this guide on React event handling.
Render a Static Array in a Component
Components often render lists from arrays. A support dashboard might begin with a static array while you design the UI.
const recentTickets = [
{ id: 101, title: "Login issue", priority: "High" },
{ id: 102, title: "Invoice not received", priority: "Medium" },
{ id: 103, title: "Profile update request", priority: "Low" }
];
function RecentTickets() {
return (
<section>
<h2>Recent Tickets</h2>
{recentTickets.map((ticket) => (
<article key={ticket.id}>
<h3>{ticket.title}</h3>
<p>Priority: {ticket.priority}</p>
</article>
))}
</section>
);
}
The JavaScript map() method creates a new array by running a function for every ticket. Here, it creates one <article> for each ticket.
The key prop gives each rendered item a stable identity. React uses keys to track items when the list changes. Use a unique database ID whenever possible.
Avoid using the array index as a key if users can add, remove, sort, or reorder items. A stable ID prevents React from connecting the wrong data to the wrong rendered row.
How Components Work Together
A real React screen usually has a component tree. The top-level component renders child components, and those children can render more components.
Here is a simple structure:
function App() {
return (
<Dashboard>
<RecentTickets />
</Dashboard>
);
}
function Dashboard({ children }) {
return (
<main className="dashboard">
<h1>Support Dashboard</h1>
{children}
</main>
);
}
The children prop represents JSX placed between a component’s opening and closing tags. In this example, Dashboard wraps RecentTickets.
This pattern helps you build reusable layout components. You can use Dashboard again with a different child section later.
For more examples of organizing a screen, explore this guide on React app component structure.
Build a Practical Ticket List Component
Let’s combine props, state, and list rendering in a simple ticket list.
import { useState } from "react";
function TicketList() {
const [tickets, setTickets] = useState([
{ id: 1, title: "Password reset", status: "Open" },
{ id: 2, title: "Billing question", status: "Resolved" },
{ id: 3, title: "Cannot upload file", status: "Open" }
]);
function markResolved(ticketId) {
const updatedTickets = tickets.map((ticket) => {
if (ticket.id === ticketId) {
return { ...ticket, status: "Resolved" };
}
return ticket;
});
setTickets(updatedTickets);
}
return (
<section>
<h2>Support Tickets</h2>
{tickets.map((ticket) => (
<TicketRow
key={ticket.id}
ticket={ticket}
onResolve={markResolved}
/>
))}
</section>
);
}
function TicketRow({ ticket, onResolve }) {
return (
<article className="ticket-row">
<h3>{ticket.title}</h3>
<p>Status: {ticket.status}</p>
{ticket.status === "Open" && (
<button onClick={() => onResolve(ticket.id)}>
Mark as resolved
</button>
)}
</article>
);
}
export default TicketList;
I executed the above example code and added the screenshot below.

The TicketList component owns the ticket state because it needs to update tickets. It passes each ticket and the markResolved function to TicketRow.
TicketRow stays simple. It displays one ticket and notifies its parent when the user clicks the button. This is a common React pattern: keep shared, changing data in the closest parent component that needs it.
Notice that markResolved uses map() and the spread operator (...ticket) to create a new array and a new ticket object. That approach avoids state mutation, which means changing existing state directly.
React works best when you create new state values instead of modifying current ones.
Pro Tip: I keep state updates predictable by treating state as read-only. When I update one row in a dashboard, I create a new array and a new object for that row. It makes debugging far easier when the UI grows.
Use Components for API Data
Most production dashboards load data from an API instead of a hardcoded array. In React, you often use useEffect to run code after the component renders.
useEffect is a React Hook for handling side effects. A side effect is work outside rendering, such as loading API data, setting up a subscription, or updating the document title.
import { useEffect, useState } from "react";
function TicketList() {
const [tickets, setTickets] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function loadTickets() {
const response = await fetch("/api/tickets");
const data = await response.json();
setTickets(data);
setLoading(false);
}
loadTickets();
}, []);
if (loading) {
return <p>Loading tickets...</p>;
}
return (
<section>
<h2>Recent Tickets</h2>
{tickets.map((ticket) => (
<TicketRow key={ticket.id} ticket={ticket} />
))}
</section>
);
}
The empty dependency array [] tells React to run this effect after the first render. The component starts with an empty ticket array, loads the data, and updates state after the response arrives.
In a production app, also handle request failures and unexpected responses. If your API data does not a