Master React project structure to keep your codebase organized. Learn how to separate components, hooks, and services to ensure long-term scalability.
Previously in this course, we explored Refactoring for Clean Code: Improving React Maintainability, where we focused on cleaning up individual component logic. Now that your code is cleaner, it's time to ensure your project's physical layout supports that cleanliness as your app grows.
A disorganized project structure is the silent killer of productivity. When you spend five minutes hunting for a single file, you lose focus. By following consistent folder organization, you build a foundation that scales alongside your features.
As your movie-browser app grows from a few components to dozens, dumping everything into a single src folder becomes unmanageable. A professional project structure provides a "mental map" for your codebase. When a new developer (or your future self) joins the project, they should be able to intuit where a specific piece of logic lives without reading every file.
Scalability isn't just about handling more data; it's about handling more complexity without introducing bugs. Modularizing your project helps you isolate concerns, making it easier to test components and swap out implementations.
For most React applications, I recommend a structure that groups files by responsibility rather than by feature initially, as it provides a clear separation of concerns.
Here is the standard layout we will adopt for our movie-browser app:
TEXTsrc/ ├── components/ # Reusable UI building blocks (e.g., MovieCard, SearchBar) ├── hooks/ # Custom React hooks (e.g., useFetch, useLocalStorage) ├── services/ # API calls and external data fetching logic ├── utils/ # Helper functions (e.g., date formatters, API constants) ├── assets/ # Images, fonts, or global CSS ├── App.jsx # Root component └── main.jsx # Entry point
This folder contains your presentational components. If a component is specific to a single page, you might create a sub-folder: components/movie/MovieCard.jsx. Keep this folder strictly for UI logic.
When you extract logic from your components (like we discussed in our Refactoring for Clean Code lesson), move those reusable functions here. Prefix them with use, such as useMovieSearch.js.
Never put API fetching logic directly inside a useEffect if you can avoid it. Instead, create a service file like services/movieService.js that exports functions like fetchMovies(query). This keeps your components focused on rendering, not network protocol details.
Let's refactor a part of our movie-browser. Previously, we might have had our fetch call sitting inside a useEffect in our App.jsx. That is a "leaky abstraction."
Before:
JSX// App.jsx - Too much going on! useEffect(() => { fetch(CE9178">`https://api.example.com/movies?q=${query}`) .then(res => res.json()) .then(data => setMovies(data)); }, [query]);
After:
First, create src/services/movieService.js:
JAVASCRIPTexport const getMovies = async (query) => { const response = await fetch(CE9178">`https://api.example.com/movies?q=${query}`); if (!response.ok) throw new Error("Failed to fetch"); return response.json(); };
Then, import it into your component:
JSXimport { getMovies } from CE9178">'./services/movieService'; // Inside your component useEffect(() => { getMovies(query).then(setMovies); }, [query]);
services directory inside your src folder.movieService.js within that directory.components/ui/buttons/primary/large/, you've over-engineered it.PascalCase for components (MovieCard.jsx) and camelCase for hooks and services (useFetch.js, movieService.js).utils folder: If you have a function that formats dates or cleans strings, don't leave it inside a component. Put it in utils/formatters.js so it can be tested in isolation.A clean project structure is the difference between a project that's a joy to work on and one that feels like a chore. By separating your UI components, business logic (services), and reusable hooks, you ensure that your code is modular, testable, and ready for whatever features you add next. Remember: folder organization is a living process; it's okay to move files as your understanding of the app's architecture evolves.
Up next: We will continue our refactoring journey by taking the logic we just moved and turning it into a truly reusable custom hook.
Master the art of UI state management by adding a filter toggle to your movie app. Learn to control list rendering using boolean state and checkbox inputs.
Folder Structure Best Practices
Review of Component Lifecycle
Review of State Management
Building a Modal Component
Introduction to PropTypes
Performance Optimization Basics
Handling Browser History
Working with LocalStorage
Building a Favorites List
Handling Media in React
Introduction to Testing
Debugging React Apps
Deployment Basics
Using External Libraries
Advanced