Skip to main content

React Code Organization

Overview

As our application grows, maintainability becomes more important than writing code quickly.

Every file should have a single responsibility. Components should focus on rendering UI, while business logic, validation, schemas, and API calls should be separated into their own modules.

Core Principles

  • Keep files small.
  • One responsibility per file.
  • Separate UI from business logic.
  • Separate schemas from validation.
  • Separate API calls from components.
  • Prefer composition over large components.
  • Build reusable components whenever possible.

File Size Guidelines

File SizeRecommendation
Less than 300 lines✅ Ideal
300 to 500 lines⚠️ Consider splitting
More than 500 lines❌ Refactor required
More than 1000 lines🚨 Not acceptable

Single Responsibility Principle

Each file should have one purpose.

❌ Bad

One file contains:

  • UI
  • API calls
  • Validation
  • Form schema
  • Business logic
  • Utility functions

✅ Good

Separate them into:

  • Component
  • Schema
  • Validation
  • Service
  • Hook

Component Guidelines

A React component should only be responsible for rendering UI and handling local interactions.

A component should:

  • Render the interface
  • Accept props
  • Manage local state
  • Call hooks

A component should not:

  • Perform API requests directly
  • Contain validation logic
  • Define large form schemas
  • Contain unrelated business logic

Schema Organization

Never place every schema inside one file.

❌ Bad

candidate-schema.ts

Basic Information
Experience
Projects
Skills
Education
Languages
Achievements

Large schema files quickly become difficult to maintain.

✅ Good

schemas/

basic-information.ts
experience.ts
projects.ts
skills.ts
education.ts
languages.ts
achievements.ts
index.ts

Example:

export const basicInformationSchema = [
{
name: "firstName",
type: "text",
label: "First Name",
},
];

API Layer

React components should never communicate directly with the backend.

❌ Bad

await axios.post("/candidate", data);

✅ Good

// candidate.service.ts

export async function updateCandidate(data) {
return api.patch("/candidate", data);
}

Inside the component:

await updateCandidate(formData);

Custom Hooks

Business logic belongs inside hooks.

Example:

hooks/

useCandidate.ts
useProjects.ts
useProfile.ts

Hooks should contain:

  • Data fetching
  • Mutations
  • Derived state
  • Complex business logic

Components should remain focused on rendering.

Reusable Field Definitions

Avoid repeating field definitions.

Instead of:

{
type: "text",
name: "firstName",
label: "First Name"
}

Create reusable helpers.

textField("firstName", "First Name");

Benefits:

  • Less duplication
  • Easier maintenance
  • Consistent field definitions

Naming Conventions

Components

CandidateProfile.tsx
ExperienceSection.tsx
ProjectCard.tsx

Use PascalCase.

Hooks

useCandidate.ts
useProjects.ts

Always start hook names with use.

Services

candidate.service.ts
auth.service.ts

Schemas

basic-information.ts
experience.ts
projects.ts

Use kebab-case.

Types

candidate.types.ts
project.types.ts

Component Size

If a component is responsible for:

  • Rendering UI
  • Fetching data
  • Validation
  • API calls
  • Business logic
  • State management

It should be split into multiple files.

ItemRecommendation
ComponentAround 300 lines or less
HookAround 200 lines or less
ServiceAround 200 lines or less
SchemaOne section per file
ValidationOne section per file

Example

Instead of:

CandidateEdit.tsx

1200 lines

Prefer:

CandidateEdit.tsx

components/
BasicInformationSection.tsx
ExperienceSection.tsx
SkillsSection.tsx
ProjectsSection.tsx

schemas/

validation/

hooks/

services/

Each file should have one clear responsibility.

Benefits

Following these guidelines provides several advantages:

  • Easier code reviews
  • Fewer merge conflicts
  • Better readability
  • Better testability
  • Faster onboarding for new developers
  • Easier feature development
  • More reusable code

Summary

  • Keep files focused.
  • Keep components small.
  • One responsibility per file.
  • Separate UI from business logic.
  • Separate schemas from validation.
  • Keep API calls inside services.
  • Keep business logic inside hooks.
  • Reuse components and helper functions whenever possible.