Component Architecture Implementation Patterns
1. React Functional Components Hooks
| Hook | Syntax | Description | Use Case |
|---|---|---|---|
| useState | const [state, setState] = useState(initial) |
Manages component local state with immutable updates | Form inputs, toggles, counters |
| useEffect | useEffect(() => {}, [deps]) |
Handles side effects, subscriptions, data fetching | API calls, DOM manipulation, subscriptions |
| useContext | const value = useContext(Context) |
Consumes React context without wrapper components | Theme, auth, global state access |
| useReducer | const [state, dispatch] = useReducer(reducer, init) |
Complex state logic with predictable state transitions | Form validation, multi-step wizards |
| useMemo | const value = useMemo(() => compute(), [deps]) |
Memoizes expensive computations between renders | Large list filtering, complex calculations |
| useCallback | const fn = useCallback(() => {}, [deps]) |
Memoizes function references to prevent re-renders | Event handlers in optimized children |
| useRef | const ref = useRef(initialValue) |
Persists mutable value without triggering re-renders | DOM access, storing previous values |
| useLayoutEffect | useLayoutEffect(() => {}, [deps]) |
Synchronous effect before browser paint | DOM measurements, animations |
Example: Complete functional component with hooks
import { useState, useEffect, useCallback, useMemo } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUser = async () => {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
setLoading(false);
};
fetchUser();
}, [userId]);
const handleUpdate = useCallback((updates) => {
setUser(prev => ({ ...prev, ...updates }));
}, []);
const displayName = useMemo(() =>
user ? `${user.firstName} ${user.lastName}` : 'Unknown',
[user]
);
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>{displayName}</h1>
<button onClick={() => handleUpdate({ active: true })}>
Activate
</button>
</div>
);
}
2. Vue 3 Composition API Setup
| Function | Syntax | Description | Use Case |
|---|---|---|---|
| ref | const count = ref(0) |
Creates reactive primitive value with .value access | Simple reactive state |
| reactive | const state = reactive({}) |
Creates deeply reactive object proxy | Complex nested state |
| computed | const doubled = computed(() => count.value * 2) |
Cached derived state recalculated on dependency change | Derived values, filters |
| watch | watch(source, (newVal, oldVal) => {}) |
Performs side effects on reactive state changes | API calls on input change |
| watchEffect | watchEffect(() => console.log(count.value)) |
Automatically tracks dependencies and runs immediately | Logging, analytics |
| onMounted | onMounted(() => {}) |
Lifecycle hook after component DOM insertion | Initialize third-party libraries |
| provide/inject | provide('key', value); const val = inject('key') |
Dependency injection without prop drilling | Plugin systems, themes |
Example: Vue 3 Composition API component
<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue';
const count = ref(0);
const user = reactive({
name: 'John',
email: 'john@example.com'
});
const displayName = computed(() =>
user.name.toUpperCase()
);
watch(count, (newCount, oldCount) => {
console.log(`Count changed from ${oldCount} to ${newCount}`);
});
onMounted(() => {
console.log('Component mounted');
});
const increment = () => count.value++;
</script>
<template>
<div>
<h1>{{ displayName }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
3. Angular 17 Standalone Components NEW
| Feature | Syntax | Description | Use Case |
|---|---|---|---|
| @Component | @Component({ standalone: true }) |
Self-contained component without NgModule | Modern Angular architecture |
| imports | imports: [CommonModule, FormsModule] |
Direct dependency declaration in component | Explicit dependency management |
| Signal | count = signal(0) |
Fine-grained reactive primitive for change detection | Performance optimization |
| computed | doubled = computed(() => count() * 2) |
Derived signal automatically updated | Calculated values |
| effect | effect(() => console.log(count())) |
Side effects triggered by signal changes | Logging, analytics |
| Input/Output | @Input() data; @Output() changed = new EventEmitter() |
Component communication interface | Parent-child data flow |
Example: Angular 17 standalone component with signals
import { Component, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-counter',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<div>
<h2>Counter: {{ count() }}</h2>
<p>Doubled: {{ doubled() }}</p>
<button (click)="increment()">Increment</button>
<button (click)="decrement()">Decrement</button>
</div>
`
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
increment() {
this.count.update(n => n + 1);
}
decrement() {
this.count.update(n => n - 1);
}
}
4. Atomic Design System Storybook
| Level | Component Type | Description | Examples |
|---|---|---|---|
| Atoms | Basic building blocks | Smallest functional units, not divisible | Button, Input, Label, Icon |
| Molecules | Simple groups | Combinations of atoms functioning together | SearchBar, FormField, Card |
| Organisms | Complex sections | Complex UI sections with distinct functionality | Header, Footer, ProductCard |
| Templates | Page layouts | Page-level structure without real content | HomePageLayout, DashboardLayout |
| Pages | Instances | Templates with real content and data | HomePage, UserProfilePage |
Example: Storybook configuration and component story
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Atoms/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger']
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg']
}
}
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Click Me',
size: 'md'
}
};
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'Cancel',
size: 'md'
}
};
// SearchBar.stories.tsx (Molecule)
import { SearchBar } from './SearchBar';
export default {
title: 'Molecules/SearchBar',
component: SearchBar
};
export const Default = () => <SearchBar placeholder="Search..." />;
Note: Storybook v7+ uses CSF3 format with improved
TypeScript support and automatic documentation generation.
5. Props Interface TypeScript Definitions
| Pattern | Syntax | Description | Use Case |
|---|---|---|---|
| Basic Interface | interface Props { name: string } |
Type-safe prop definitions | Component contracts |
| Optional Props | title?: string |
Props that can be undefined | Non-required attributes |
| Default Props | name = 'Guest' |
Fallback values for props | Default configurations |
| Union Types | variant: 'primary' | 'secondary' |
Restricted string literal values | Variant options |
| Generic Props | interface Props<T> { data: T } |
Reusable type-safe components | List, Table components |
| Children Prop | children: React.ReactNode |
Type for child elements | Container components |
| Event Handlers | onClick: (e: MouseEvent) => void |
Type-safe event callbacks | Interactive elements |
| Extending Props | interface Props extends HTMLAttributes<T> |
Inherit native HTML props | Wrapper components |
Example: Comprehensive TypeScript component interfaces
// Basic Props Interface
interface ButtonProps {
variant: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
children: React.ReactNode;
}
function Button({
variant,
size = 'md',
disabled = false,
onClick,
children
}: ButtonProps) {
return (
<button
className={`btn btn-${variant} btn-${size}`}
disabled={disabled}
onClick={onClick}
>
{children}
</button>
);
}
// Generic Props with Type Parameter
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyExtractor: (item: T) => string | number;
}
function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
return (
<ul>
{items.map(item => (
<li key={keyExtractor(item)}>
{renderItem(item)}
</li>
))}
</ul>
);
}
// Extending HTML Attributes
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label: string;
error?: string;
}
function Input({ label, error, ...props }: InputProps) {
return (
<div>
<label>{label}</label>
<input {...props} />
{error && <span className="error">{error}</span>}
</div>
);
}
6. Component Composition Higher-Order Components
| Pattern | Description | Use Case | Example |
|---|---|---|---|
| HOC Pattern | Function that takes component, returns enhanced component | Cross-cutting concerns, auth | withAuth(Component) |
| Render Props | Component shares code via function prop | Dynamic rendering logic | <Toggle render={(on) => ...} /> |
| Compound Components | Multiple components work together as single unit | Flexible APIs like Select/Option | <Select><Option/></Select> |
| Container/Presentational | Separate data logic from UI rendering | Reusable UI components | UserContainer + UserView |
| Custom Hooks | Reusable stateful logic extraction | Shared behavior across components | useAuth(), useFetch() |
Example: HOC for authentication and loading states
// Higher-Order Component Pattern
function withAuth<P extends object>(
Component: React.ComponentType<P>
) {
return function AuthenticatedComponent(props: P) {
const { user, loading } = useAuth();
if (loading) return <div>Loading...</div>;
if (!user) return <Navigate to="/login" />;
return <Component {...props} user={user} />;
};
}
// Usage
const ProtectedDashboard = withAuth(Dashboard);
// Render Props Pattern
function DataFetcher({ url, render }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
});
}, [url]);
return render({ data, loading });
}
// Usage
<DataFetcher
url="/api/users"
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>
// Compound Components Pattern
const Select = ({ children, value, onChange }) => {
return (
<div className="select">
{React.Children.map(children, child =>
React.cloneElement(child, { selected: value, onSelect: onChange })
)}
</div>
);
};
Select.Option = ({ value, selected, onSelect, children }) => (
<div
className={selected === value ? 'selected' : ''}
onClick={() => onSelect(value)}
>
{children}
</div>
);
// Usage
<Select value={selected} onChange={setSelected}>
<Select.Option value="1">Option 1</Select.Option>
<Select.Option value="2">Option 2</Select.Option>
</Select>
Component Architecture Best Practices
- Hooks preferred over class components in modern React for better composition
- Use TypeScript interfaces for type-safe prop validation
- Follow Atomic Design for consistent component hierarchy
- Storybook essential for component development and documentation
- Choose composition pattern based on reusability needs: HOC for cross-cutting, Render Props for dynamic logic, Compound for flexible APIs