Author
A well-structured React project is like a well-organized workspace — it saves time, reduces bugs, and makes collaboration easier. Whether you’re building a small app or a large-scale enterprise project, following clean architecture and consistent coding standards ensures your code remains maintainable, scalable, and easy to understand.
A good project structure helps you:
Poor structure, on the other hand, can make even small projects messy and difficult to maintain as they grow.
Here’s a commonly used, scalable folder structure for modern React projects:
src/
├── assets/ # Images, icons, fonts, videos
├── components/ # Reusable UI components (Buttons, Inputs, Cards)
├── pages/ # Page-level components (Home, About, Dashboard)
├── hooks/ # Custom React Hooks (useAuth, useFetch)
├── context/ # Context API files (ThemeContext, AuthContext)
├── store/ # Redux, Zustand, or Recoil state management
├── services/ # API calls and external services
├── utils/ # Helper functions and utilities
├── styles/ # Global CSS, SCSS, or styled-components themes
├── routes/ # App routing configuration
├── constants/ # App-wide constants and config variables
├── App.js # Root component
├── index.js # Entry point for ReactDOM.render
└── setupTests.js # Jest/RTL configuration
components/ → Contains small, reusable building blocks like Button, Navbar, or Modalpages/ → Represents full-page views like HomePage, LoginPage, or ProfilePagehooks/ → Stores reusable custom hooks such as useForm or useFetchservices/ → Central place for API logic using Axios or Fetchcontext/ → Defines global app contexts (e.g., Theme, Auth)store/ → Manages state if using Redux Toolkit or Zustandutils/ → Contains helper functions (e.g., formatDate, validateEmail)styles/ → Centralized styling for consistent UI themesUserProfile.jsuseAuth.jsuser-icon.svgAPI_BASE_URLExample:
// Good
function UserCard() {}
// Bad
function user_card() {}
Instead of having one massive components folder, group related files by feature or domain.
src/
└── features/
├── auth/
│ ├── LoginPage.jsx
│ ├── RegisterPage.jsx
│ ├── AuthContext.js
│ └── authService.js
├── dashboard/
│ ├── DashboardPage.jsx
│ ├── ChartWidget.jsx
│ └── dashboardService.js
This makes it easier to maintain large applications as each feature is self-contained.
Maintaining consistency in your code style helps teams write clean, readable, and error-free code.
Here are some key standards to follow:
Install and configure ESLint and Prettier to automatically format and lint your code.
Example (ESLint + Prettier setup):
npm install eslint prettier eslint-config-prettier eslint-plugin-react --save-dev
Then create a .eslintrc.json file:
{
"extends": ["react-app", "prettier"],
"plugins": ["react"],
"rules": {
"react/prop-types": "off",
"no-unused-vars": "warn"
}
}
here,
Each component should handle one responsibility.
Avoid:
function Dashboard() {
// Handles API calls, rendering charts, managing modals, etc.
}
Instead, split logic:
function Dashboard() {
return (
<><DashboardHeader />
<UserStats />
<RecentActivities />
</>
);
}
Example:
// Good
const [userData, setUserData] = useState([]);
// Bad
const [a, b] = useState([]);
Keep data fetching and business logic separate from UI rendering.
Mixing logic inside components:
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return users.map(u => <p>{u.name}</p>);
}
Better approach:
// useUsers.js
export function useUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return users;
}
// UserList.jsx
import { useUsers } from "../hooks/useUsers";
function UserList() {
const users = useUsers();
return users.map(u => <p>{u.name}</p>);
}
Use PropTypes or TypeScript for validating props and ensuring type safety.
import PropTypes from "prop-types";
function UserCard({ name, age }) {
return <div>{name} – {age}</div>;
}
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
};
or with TypeScript:
type UserCardProps = {
name: string;
age?: number;
};
const UserCard = ({ name, age }: UserCardProps) => (
<div>{name} – {age}</div>
);
Use:
git commit often and write clear messages)src/
├── api/
│ └── axiosInstance.js
├── components/
│ ├── Button.jsx
│ ├── Card.jsx
│ └── Modal.jsx
├── context/
│ └── AuthContext.js
├── hooks/
│ ├── useAuth.js
│ └── useFetch.js
├── pages/
│ ├── Home.jsx
│ ├── Login.jsx
│ └── Dashboard.jsx
├── store/
│ └── index.js
├── styles/
│ ├── globals.css
│ └── variables.scss
└── utils/
└── formatDate.js
| Practice | Benefit |
|---|---|
| Organized folder structure | Easy navigation and scalability |
| ESLint + Prettier | Consistent and clean code |
| Small, focused components | Reusable and testable |
| Separation of logic and UI | Better maintainability |
| Type checking | Fewer runtime errors |
| Documentation & Git | Easier collaboration |