Faster Development
Leverage existing components to build new features quickly.
Reusability focuses on creating code components that can be used multiple times across different parts of an application or even across different projects, reducing duplication and increasing development efficiency.
Reusability is the ability to use existing software components in new applications or contexts without modification, or with minimal changes. It’s about designing flexible, modular code that solves problems in a general way.
Faster Development
Leverage existing components to build new features quickly.
Consistency
Uniform behavior and appearance across the application.
Easier Maintenance
Fix bugs and add features in one place, benefiting all uses.
Cost Efficiency
Reduce development time and resources needed for new projects.
Creating functions, classes, and modules that can be used in multiple contexts:
// Reusable utility functionsexport const formatCurrency = (amount, currency = 'USD') => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency }).format(amount);};
export const debounce = (func, delay) => {let timeoutId;return (...args) => {clearTimeout(timeoutId);timeoutId = setTimeout(() => func.apply(null, args), delay);};};
export const deepClone = (obj) => {if (obj === null || typeof obj !== 'object') return obj;if (obj instanceof Date) return new Date(obj.getTime());if (obj instanceof Array) return obj.map(item => deepClone(item));
const cloned = {};for (let key in obj) {if (obj.hasOwnProperty(key)) {cloned[key] = deepClone(obj[key]);}}return cloned;};// Reusable class with configurable behaviorclass DataValidator { constructor(rules = {}) { this.rules = rules; }
validate(data) { const errors = [];
for (const [field, fieldRules] of Object.entries(this.rules)) { const value = data[field];
if (fieldRules.required && !value) { errors.push(`${field} is required`); }
if (fieldRules.minLength && value.length < fieldRules.minLength) { errors.push(`${field} must be at least ${fieldRules.minLength} characters`); }
if (fieldRules.pattern && !fieldRules.pattern.test(value)) { errors.push(`${field} format is invalid`); } }
return { isValid: errors.length === 0, errors }; }}
// Usageconst userValidator = new DataValidator({ email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ }, password: { required: true, minLength: 8 }});Building UI components that can be used across different pages and applications:
// Reusable Button componentconst Button = ({ variant = 'primary', size = 'medium', children, onClick, disabled = false, ...props}) => { const baseClasses = 'px-4 py-2 rounded font-medium transition-colors'; const variantClasses = { primary: 'bg-blue-600 text-white hover:bg-blue-700', secondary: 'bg-gray-600 text-white hover:bg-gray-700', danger: 'bg-red-600 text-white hover:bg-red-700' }; const sizeClasses = { small: 'px-2 py-1 text-sm', medium: 'px-4 py-2', large: 'px-6 py-3 text-lg' };
return ( <button className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`} onClick={onClick} disabled={disabled} {...props} > {children} </button> );};
// Usage across different contexts<Button variant="primary" onClick={handleSave}>Save</Button><Button variant="danger" onClick={handleDelete}>Delete</Button><Button variant="secondary" size="small">Cancel</Button>Implementing reusable architectural patterns:
// Factory Pattern for creating different types of loggersclass LoggerFactory { static createLogger(type, config = {}) { switch (type) { case "console": return new ConsoleLogger(config); case "file": return new FileLogger(config); case "remote": return new RemoteLogger(config); default: throw new Error(`Unknown logger type: ${type}`); } }}
// Strategy Pattern for different payment methodsclass PaymentProcessor { constructor(strategy) { this.strategy = strategy; }
processPayment(amount, details) { return this.strategy.process(amount, details); }}
const creditCardStrategy = { process: (amount, details) => { // Credit card processing logic return { success: true, transactionId: "cc_123" }; },};
const paypalStrategy = { process: (amount, details) => { // PayPal processing logic return { success: true, transactionId: "pp_456" }; },};Each component should have one clear purpose:
// ❌ Component doing too many thingsconst UserProfileManager = () => { // Handles user data, validation, API calls, UI rendering};
// ✅ Separated concernsconst UserProfile = ({ user }) => { /* UI only */};const useUserData = () => { /* Data management */};const useUserValidation = () => { /* Validation logic */};Make components configurable rather than hardcoded:
// ❌ Hardcoded behaviorconst Modal = ({ children }) => { return ( <div className="fixed inset-0 bg-black bg-opacity-50"> <div className="bg-white p-6 rounded max-w-md mx-auto mt-20"> {children} </div> </div> );};
// ✅ Configurable behaviorconst Modal = ({ children, isOpen = false, onClose, size = "medium", backdrop = true, className = "", ...props}) => { if (!isOpen) return null;
const sizeClasses = { small: "max-w-sm", medium: "max-w-md", large: "max-w-lg", full: "max-w-full", };
return ( <div className={`fixed inset-0 z-50 ${backdrop ? "bg-black bg-opacity-50" : ""}`} onClick={onClose} > <div className={`bg-white p-6 rounded ${sizeClasses[size]} mx-auto mt-20 ${className}`} onClick={(e) => e.stopPropagation()} {...props} > {children} </div> </div> );};Define clear interfaces for reusable components:
interface ButtonProps { variant?: "primary" | "secondary" | "danger"; size?: "small" | "medium" | "large"; disabled?: boolean; loading?: boolean; onClick?: (event: MouseEvent) => void; children: React.ReactNode; className?: string;}
interface ApiResponse<T> { data: T; success: boolean; message?: string; errors?: string[];}Higher-Order Components
Wrap components to add common functionality.
Render Props
Share code between components using props.
Custom Hooks
Extract and share stateful logic between components.
Composition
Build complex functionality from simple, reusable parts.
Consider these metrics to assess reusability:
Effective documentation is crucial for reusable components:
/** * A flexible data table component with sorting, filtering, and pagination * * @param {Array} data - Array of objects to display * @param {Array} columns - Column definitions with keys and headers * @param {Object} options - Configuration options * @param {boolean} options.sortable - Enable column sorting (default: true) * @param {boolean} options.filterable - Enable row filtering (default: false) * @param {number} options.pageSize - Number of rows per page (default: 10) * * @example * <DataTable * data={users} * columns={[ * { key: 'name', header: 'Name' }, * { key: 'email', header: 'Email' } * ]} * options={{ sortable: true, pageSize: 25 }} * /> */const DataTable = ({ data, columns, options = {} }) => { // Implementation};