UTA DevHub

Component Patterns

Best practices and patterns for building reusable, maintainable React Native components

Component Patterns

Executive Summary

This document outlines standardized patterns for building React Native components in our application. It covers component organization, TypeScript integration, performance optimization, and testing strategies. Following these patterns ensures consistency, maintainability, and optimal performance across the codebase.

Component Development Philosophy

Our component architecture emphasizes:

  • Reusability: Build once, use everywhere
  • Type Safety: Full TypeScript coverage
  • Performance: Optimized for 60fps
  • Testability: Easy to test in isolation
  • Accessibility: Inclusive by default

Purpose & Scope

  • Target Audience: React Native developers building UI components for the application
  • Problems Addressed: Component reusability, type safety, performance optimization, and testing complexity
  • Scope Boundaries: Covers component architecture, patterns, and best practices but not state management or business logic implementation

Guide Sections

This comprehensive guide is organized into focused sections:

📋 Component Architecture

Fundamental patterns and organization strategies:

  • Directory structure and file organization
  • Component types (Pure, Container/Presenter, Compound, HOC, Render Props)
  • Data flow patterns
  • Architecture diagrams

📘 TypeScript Patterns

Type-safe component development:

  • Props interface patterns
  • Generic components
  • Discriminated unions
  • Advanced TypeScript techniques

Performance Optimization

Building high-performance components:

  • Memoization strategies
  • Lazy loading patterns
  • Virtualization techniques
  • Bundle size optimization

🧪 Testing Strategies

Comprehensive testing approaches:

  • Component testing patterns
  • Hook testing
  • Visual regression testing
  • Testing best practices

Component Organization

Standard Directory Structure

ComponentName.tsx
styles.ts
types.ts
index.ts

File Responsibilities

// ComponentName.tsx - Main component implementation
export const ComponentName: React.FC<ComponentNameProps> = ({ prop1, prop2 }) => {
  // Component logic
  return <View>...</View>;
};
 
// styles.ts - Component styles
import { StyleSheet } from 'react-native';
export const styles = StyleSheet.create({
  container: { flex: 1 },
});
 
// types.ts - Component types and interfaces
export interface ComponentNameProps {
  prop1: string;
  prop2?: number;
  onPress?: () => void;
}
 
// index.ts - Barrel export
export { ComponentName } from './ComponentName';
export type { ComponentNameProps } from './types';

Quick Examples

Pure Functional Component

For a complete example of a pure functional component with all features, see the Button Component.

Key patterns demonstrated:

  • ✅ Pure functional component with TypeScript
  • ✅ Props interface with proper defaults
  • ✅ Design token integration
  • ✅ Accessibility implementation
  • ✅ Loading and disabled states

Container/Presenter Pattern

// Container handles data and logic
export const ProductListContainer: React.FC = () => {
  const { data: products, isLoading, error } = useProducts();
 
  if (isLoading) return <LoadingView />;
  if (error) return <ErrorView error={error} />;
 
  return <ProductList products={products} />;
};
 
// Presenter handles UI rendering
export const ProductList: React.FC<ProductListProps> = ({ products }) => {
  return (
    <FlatList
      data={products}
      renderItem={({ item }) => <ProductCard product={item} />}
    />
  );
};

Design Principles

Core Principles

  1. Single Responsibility: Each component should do one thing well
  2. Composition over Inheritance: Build complex UIs from simple components
  3. Props over State: Prefer controlled components
  4. Type Safety: Full TypeScript coverage
  5. Performance First: Optimize for 60fps

Component Decision Matrix

PatternBenefitsDrawbacksUse When
Container/PresenterClear separationMore filesComplex state logic
Compound ComponentsFlexible APIMore complexMulti-part components
Render PropsMaximum flexibilityVerbose syntaxDynamic rendering
HOCsReusable logicWrapper hellCross-cutting concerns

Best Practices Summary

Component Development Checklist

  • ✅ Use TypeScript for all components
  • ✅ Include accessibility props
  • ✅ Export types alongside components
  • ✅ Optimize for performance
  • ✅ Write comprehensive tests
  • ✅ Document complex patterns
  • ✅ Follow naming conventions

Quick Do's and Don'ts

  • (Do ✅) Keep components focused on a single responsibility
  • (Do ✅) Provide sensible default props
  • (Do ✅) Use design tokens for styling
  • (Don't ❌) Put business logic in presentational components
  • (Don't ❌) Use inline styles for complex styling
  • (Don't ❌) Create deeply nested component structures
  • (Consider 🤔) Breaking large components into smaller ones
  • (Be Aware ❗) Of performance implications for list items

Summary

Effective component patterns ensure:

  1. Consistent structure across the codebase
  2. Reusable and testable components
  3. Type-safe implementations
  4. Performance optimizations
  5. Clear separation of concerns

Following these patterns creates a maintainable, scalable UI architecture.