ReactJS Architecture

Core Architectural Concepts

React's flexible architecture allows for scalable application design while maintaining performance and developer experience.

Component-Based Architecture

  • UI broken into independent, reusable components
  • Components manage their own state and UI
  • Composition over inheritance
  • Unidirectional data flow (parent → child)
function Parent() {
  return (
    <div>
      <ChildA />
      <ChildB />
    </div>
  );
}

Virtual DOM

  • Lightweight copy of actual DOM
  • Diffing algorithm calculates minimal updates
  • Batch updates for performance
  • Reconciliation process determines DOM changes
State Change →
Virtual DOM Comparison →
Minimal DOM Updates

Application Structure Patterns

1. Atomic Design

Atoms

Basic UI elements (buttons, inputs)

<Button />

Molecules

Groups of atoms (search bar)

<SearchBar />

Organisms

Complex components (header, sidebar)

<PageHeader />

Templates

Page layouts

<DashboardLayout />

Pages

Final UI with real data

<DashboardPage />

2. Feature-Based Structure

src/
  features/
    user/
      components/
      hooks/
      services/
      userSlice.js
    products/
      components/
      hooks/
      services/
      productSlice.js
  shared/
    components/
    utils/
    hooks/

Groups all files related to a feature together for better maintainability.

3. Layered Architecture

src/
  presentation/  // UI components
  domain/       // Business logic
  application/  // Use cases
  infrastructure/ // API calls, storage
  shared/       // Common utilities

Separation of concerns with clear boundaries between layers.

State Management Architecture

Component State

For local UI state

const [state, setState] = useState();

Context API

Medium-scale app state

<AuthContext.Provider value={user}>

Redux

Large-scale predictable state

const store = configureStore({ reducer });

React Query

Server state management

const { data } = useQuery('todos', fetchTodos);

Recommended State Flow

1

Start with component state

2

Lift state up when sharing between siblings

3

Use Context for global app state

4

Introduce Redux when Context becomes unwieldy

Advanced Architectural Patterns

Container/Presentational

Separate logic from presentation

// Container
function UserContainer() {
  const [users] = useUsers();
  return <UserList users={users} />;
}

// Presentational
function UserList({ users }) {
  return /* UI */;
}

Compound Components

Components that work together

<Tabs>
  <TabList>
    <Tab>First</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content</TabPanel>
  </TabPanels>
</Tabs>

Render Props

Share code via props

<DataProvider render={data => (
  <h1>Hello {data.user}</h1>
)} />

Higher-Order Components

Component factories

const withAuth = (Component) => {
  return (props) => {
    if (!auth) return <Login />;
    return <Component {...props} />;
  };
};

Performance Architecture

Code Splitting

const LazyComponent = React.lazy(() => import('./Component'));
<Suspense fallback={<Loader />}>
  <LazyComponent />
</Suspense>

Memoization

const MemoComp = React.memo(Component);
const data = useMemo(() => transform(data), [data]);

Windowing

<List height={600} itemSize={35} itemCount={1000}>
  {Row}
</List>

Concurrent Rendering

const root = createRoot(container);
root.render(<App />);

Testing Architecture

Unit Tests

Individual components

test('renders button', () => {
  render(<Button />);
  expect(screen.getByRole('button')).toBeInTheDocument();
});

Integration Tests

Component interactions

test('adds item to cart', () => {
  render(<Product product={mockProduct} />);
  fireEvent.click(screen.getByText('Add to Cart'));
  expect(mockAddToCart).toHaveBeenCalled();
});

E2E Tests

Full user flows

it('completes checkout', () => {
  cy.visit('/products');
  cy.get('[data-testid="product"]').first().click();
  cy.contains('Checkout').click();
});