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.