React Code Organisation
Frontend development is messy enough as it is. Follow these rules to keep your frontend code organised and maintainable.
Componentise from the start! The reason for spreading work across files is more than just separation of concerns, it’s also about avoiding merge conflicts and creating a shared, intuitive understanding of the codebase for people who are unfamiliar with it.
It’s like self-documenting code, just at the file-system level.
File Structure
Section titled “File Structure”Normally in a Laravel project, you’ll find React code in resources/js. The different subdirectories may look like this:
Directoryjs/
Directorycomponents/
Directoryui/
- button.tsx
Directorycontext/
- …
Directoryhooks/
- …
Directorylayouts/
- …
Directorylib/
- …
Directorypages/
- …
Directoryproviders/
- …
Directorytypes/
- …
Directoryutils/
- …
Each folder has its purpose, so let’s go through them.
Self-Explanatory Directories
Section titled “Self-Explanatory Directories”Context folder is for all your React contexts. You might add a hooks to context files, for useContext wrappers (if ya nasty).
Hooks folder is for all your custom React hooks.
Layouts are for your page layouts.
Providers are for context providers. We typically don’t need these much in Laravel.
Types are for all your lovely TypeScript types!
Components
Section titled “Components”The components folder is a little nuanced, but it contains every component in the app.
The ui subdirectory comes from shadcn. It’s useful because it provides us with re-usable ‘primitive’ components that will have widespread usage throughout the rest of the app and can be composed into more complex components, i.e. form components.
Custom subdirectories should be made to group components that are feature specific. This grouping helps separation and maintainability. Often a grouping will be linked to a specific page.
Directorycomponents/
Directoryui/
- button.tsx
- dialog.tsx
- input.tsx
Directoryadmin/
- invite-user-form.tsx
- delete-user-form.tsx
Directoryprofile/
- edit-profile-dialog.tsx
While this grouping is not strict, consider the domain you’re working in, and identify good cut-points early on. You’ll get better with practice.
The pages folder contains all the pages that make up the application. Pages should contain a layout, with components inside. There should be very little logic or styling going no inside a page file. This is because the page should only be concerned with content. It’s a component or context’s job to manage business logic. It’s a layout’s job to manage layout. A page is simply responsible for content. Nothing more.
Here’s an example of a great page component:
import HeroSection from '@/components/sections/hero-section';import AboutSection from '@/components/sections/about-section';import ContactSection from '@/components/sections/contact-section';import PrimaryLayout from '@/layouts/primary-layout';import type { AboutContent } from '@/types';
export type HomePageProps = { content: AboutContent};
export default function Home({ content }: HomePageProps) { return ( <PrimaryLayout> <HeroSection /> <AboutSection content={content} /> <ContactSection /> </PrimaryLayout> );}Notice how the styling is deferred to <PrimaryLayout /> and the sections. The page component itself is just concerned about composing sections and passing content to them.
Lib vs Utils
Section titled “Lib vs Utils”Both describe utilities.
Utils folder is for universal helper functions. This are typically stateless functions like formatters, or math functions. Critically, anything in utils does not depend on any business logic or specific technology. It can be used anywhere.
This is where tools like cn live.
The lib folder is for more formalised utilities. This is where well-structured, re-usable code should live. Almost like you’re building a library that you’re going to be using in the project (hang on a minute!!).
Public Folder vs Assets Folder
Section titled “Public Folder vs Assets Folder”Public folder and assets folders are very similar, so they often get confused.
Everything in assets is going to be bundled and optimised by the bundler, especially image assets. In public, everything stays exactly as it is.
Favicons, logos and manifests should go in public.
Images, icons and other re-usable bits should go in assets.