When building React applications, beginners often write everything inside a single component. While this may work for small projects, real-world applications require structured and maintainable architecture.
Professional React projects usually separate code into:
API Layer
Service Layer
Page Components
Reusable UI Components
This separation keeps the application organized, scalable, and easy to maintain.
In this article, we will understand the concept and examine the actual code implementation using an Employee Management example.
1. How a Structured React Application Works
A well-designed React application follows this flow:
Backend API
↓
Axios API Layer
↓
Service Layer
↓
Page Component (Logic & State)
↓
UI Components (Display)
This approach ensures that each layer has a clear responsibility.
2. Project Folder Structure
A clean project structure might look like this:
src
│
├── api
│ └── axiosClient.js
│
├── services
│ └── employeeService.js
│
├── components
│ ├── Header.jsx
│ ├── EmployeeForm.jsx
│ └── EmployeeTable.jsx
│
├── pages
│ └── EmployeePage.jsx
│
├── App.js
└── index.js
Let’s understand each part with code.
3. API Layer (Axios Configuration)
The API layer centralizes API configuration.
File:
src/api/axiosClient.js
import axios from "axios";
const axiosClient = axios.create({
baseURL: "http://localhost:5288/api",
headers: {
"Content-Type": "application/json"
}
});
export default axiosClient;
Why this layer is useful
Instead of repeating API configuration everywhere, we create it once and reuse it across the application.
Later, this file can also be used for:
Adding JWT tokens
Error handling
Interceptors
4. Service Layer (Business API Calls)
The service layer communicates with the backend API.
File:
src/services/employeeService.js
import axiosClient from "../api/axiosClient";
export const getEmployees = () => {
return axiosClient.get("/Employee");
};
export const addEmployee = (data) => {
return axiosClient.post("/Employee", data);
};
export const updateEmployee = (id, data) => {
return axiosClient.put(`/Employee/${id}`, data);
};
export const deleteEmployee = (id) => {
return axiosClient.delete(`/Employee/${id}`);
};
Why this layer is important
The UI components do not call Axios directly. Instead, they call service functions.
This improves:
Code readability
Maintainability
Reusability
5. Header Component
The header is a simple UI component.
File:
src/components/Header.jsx
function Header() {
return (
<div className="bg-blue-500 text-white p-6 rounded shadow text-3xl text-center mb-6">
Employee Management
</div>
);
}
export default Header;
This component only handles UI display.
6. Employee Form Component
This component manages input fields and buttons.
File:
src/components/EmployeeForm.jsx
function EmployeeForm({
name,
department,
setName,
setDepartment,
addEmployee,
updateEmployee
}) {
return (
<div className="flex gap-4 mb-6">
<input
placeholder="Name"
className="border px-4 py-2 rounded flex-1"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<input
placeholder="Department"
className="border px-4 py-2 rounded flex-1"
value={department}
onChange={(e) => setDepartment(e.target.value)}
/>
<button
onClick={addEmployee}
className="bg-green-500 text-white px-4 py-2 rounded"
>
Add
</button>
<button
onClick={updateEmployee}
className="bg-yellow-500 text-white px-4 py-2 rounded"
>
Update
</button>
</div>
);
}
export default EmployeeForm;
This component receives data and functions from the parent component through props.
7. Employee Table Component
This component displays employee data.
File:
src/components/EmployeeTable.jsx
function EmployeeTable({ employees, editEmployee, deleteEmployee }) {
return (
<div className="overflow-x-auto bg-white p-4 rounded shadow">
<table className="w-full border">
<thead className="bg-gray-200">
<tr>
<th className="border px-4 py-2">ID</th>
<th className="border px-4 py-2">Name</th>
<th className="border px-4 py-2">Department</th>
<th className="border px-4 py-2">Actions</th>
</tr>
</thead>
<tbody>
{employees?.map(emp => (
<tr key={emp.id}>
<td className="border px-4 py-2">{emp.id}</td>
<td className="border px-4 py-2">{emp.name}</td>
<td className="border px-4 py-2">{emp.department}</td>
<td className="border px-4 py-2">
<button
onClick={() => editEmployee(emp)}
className="bg-blue-500 text-white px-3 py-1 mr-2 rounded"
>
Edit
</button>
<button
onClick={() => deleteEmployee(emp.id)}
className="bg-red-500 text-white px-3 py-1 rounded"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default EmployeeTable;
This component focuses purely on displaying the data.
8. Page Component (Main Logic Controller)
The page component manages:
File:
src/pages/EmployeePage.jsx
import React, { useEffect, useState } from "react";
import Header from "../components/Header";
import EmployeeForm from "../components/EmployeeForm";
import EmployeeTable from "../components/EmployeeTable";
import {
getEmployees,
addEmployee,
updateEmployee,
deleteEmployee
} from "../services/employeeService";
function EmployeePage() {
const [employees, setEmployees] = useState([]);
const [id, setId] = useState(null);
const [name, setName] = useState("");
const [department, setDepartment] = useState("");
useEffect(() => {
loadEmployees();
}, []);
const loadEmployees = () => {
getEmployees()
.then(res => setEmployees(res.data))
.catch(err => console.log(err));
};
const handleAdd = () => {
const data = { name, department };
addEmployee(data)
.then(() => {
loadEmployees();
setName("");
setDepartment("");
});
};
const handleDelete = (id) => {
deleteEmployee(id).then(() => loadEmployees());
};
const handleEdit = (emp) => {
setId(emp.id);
setName(emp.name);
setDepartment(emp.department);
};
const handleUpdate = () => {
const data = { id, name, department };
updateEmployee(id, data)
.then(() => {
loadEmployees();
setId(null);
setName("");
setDepartment("");
});
};
return (
<div className="min-h-screen bg-gray-100 p-6">
<Header />
<EmployeeForm
name={name}
department={department}
setName={setName}
setDepartment={setDepartment}
addEmployee={handleAdd}
updateEmployee={handleUpdate}
/>
<EmployeeTable
employees={employees}
editEmployee={handleEdit}
deleteEmployee={handleDelete}
/>
</div>
);
}
export default EmployeePage;
This file acts as the central controller of the application.
9. Key React Principle Demonstrated
This project demonstrates the concept of One-Way Data Flow.
Data moves like this:
API
↓
Service Layer
↓
Page Component
↓
UI Components
Components receive data through props and trigger actions through callback functions.
10. Conclusion
Designing React applications is not just about writing code that works. It is about organizing the application in a way that remains maintainable as it grows.
By separating the application into:
API Layer
Service Layer
Page Components
UI Components
you create a scalable architecture that is widely used in professional React applications.
This approach ensures:
Following these principles will help you build React applications that are like to real-world production systems.