Ever opened a React component and been greeted by this beautiful mess?
import React from 'react'; import { Button } from './components/ui/Button'; import { Modal } from './components/ui/Modal'; import { Input } from './components/forms/Input'; import { TextArea } from './components/forms/TextArea'; import { Card } from './components/layout/Card'; import { Header } from './components/layout/Header'; import { Footer } from './components/layout/Footer'; import { LoadingSpinner } from './components/feedback/LoadingSpinner'; import { ErrorBoundary } from './components/utils/ErrorBoundary'; import { Avatar } from './components/display/Avatar'; import { Badge } from './components/display/Badge'; import { Tooltip } from './components/overlay/Tooltip'; // ... *screams internally* π± // At this point, I'm basically importing half the internet If you've been writing React for any amount of time, you've probably seen (or written) imports like this. I know I have, and it's painful every single time. π
The Real Problem with Direct Imports
Let's be honest about what's actually happening here:
1. Import Hell
Your component files become 30% imports, 70% actual logic. New developers spend more time figuring out import paths than understanding business logic.
2. Refactoring Nightmare
Want to move your Button component from ui/ to common/? Congratulations, you now have 47 files to update. Hope you didn't miss any!
3. Inconsistent Paths
Different developers import the same component differently:
// Developer A (the relative path warrior) import { Button } from '../../../components/ui/Button'; // Developer B (the alias enthusiast) import { Button } from '@/components/ui/Button'; // Developer C (the "it works on my machine" person) import { Button } from './components/ui/Button'; // Developer D (the one who gave up) import Button from '../../../../somewhere/maybe/Button'; 4. Mental Overhead
Every time you need a component, you're playing "guess the import path" instead of focusing on solving actual problems.
The Wrapper Pattern Solution
Here's the pattern that changed everything for me:
// Before: Import spaghetti π import { Button } from './components/ui/Button'; import { Modal } from './components/ui/Modal'; import { Input } from './components/forms/Input'; // After: Zen mode activated π§ββοΈ import { Button, Modal, Input } from './components'; Step-by-Step Implementation:
Step 1: Create Your Index Files
Start with your main components directory:
// components/index.js - The hero we didn't know we needed export { Button } from './ui/Button'; export { Modal } from './ui/Modal'; export { Card } from './ui/Card'; export { Input } from './forms/Input'; export { TextArea } from './forms/TextArea'; export { Header } from './layout/Header'; export { Footer } from './layout/Footer'; // One file to rule them all π Step 2: Create Subdirectory Indexes
For better organization, create index files in subdirectories:
// components/ui/index.js - The cool kids' table export { Button } from './Button'; export { Modal } from './Modal'; export { Card } from './Card'; export { Badge } from './Badge'; export { Avatar } from './Avatar'; // components/forms/index.js - Where validation lives export { Input } from './Input'; export { TextArea } from './TextArea'; export { Select } from './Select'; export { Checkbox } from './Checkbox'; // components/layout/index.js - Structure squad export { Header } from './Header'; export { Footer } from './Footer'; export { Sidebar } from './Sidebar'; export { Container } from './Container'; Step 3: Update Your Main Index
// components/index.js - The grand finale export * from './ui'; // All the pretty things export * from './forms'; // All the input magic export * from './layout'; // All the structure export * from './utils'; // All the helper wizards Advanced Patterns
Conditional Exports
// components/index.js export { Button } from './ui/Button'; export { Card } from './ui/Card'; // Only export the secret dev tools when we're feeling rebellious π if (process.env.NODE_ENV === 'development') { export { DebugPanel } from './dev/DebugPanel'; export { ComponentX } from './dev/ComponentX'; // The files we never talk about } Named Exports with Aliases
// components/index.js - When you need to get creative with naming export { Button } from './ui/Button'; export { Button as SuperButton } from './ui/PrimaryButton'; // It's SUPER! π¦ΈββοΈ export { Modal as Dialog } from './ui/Modal'; // Same thing, different name export { Modal as PopupThingy } from './ui/Modal'; // For when you're feeling casual TypeScript Support
// components/index.ts export { Button, type ButtonProps } from './ui/Button'; export { Modal, type ModalProps } from './ui/Modal'; export { Input, type InputProps } from './forms/Input'; // Re-export types export type { ComponentSize, ComponentVariant } from './types'; Pro Tips and Best Practices
1. Keep It Organized
// β
Good: Organized like a boss export * from './ui'; // All the shiny UI stuff export * from './forms'; // Where user input goes to party export * from './layout'; // The architects of the page export * from './utils'; // The unsung heroes doing the dirty work // β Bad: Chaos incarnate export { Button } from './ui/Button'; export { validateEmail } from './utils/validation'; export { Input } from './forms/Input'; export { formatDate } from './utils/date'; // *cries in maintainability* π 2. Use Barrel Exports Wisely
// β
Good: Explicit and trustworthy export { Button } from './Button'; export { Modal } from './Modal'; // β οΈ Be careful with: The "trust me bro" approach export * from './Button'; export * from './Modal'; // Can cause circular dependencies (and developer tears) 3. Document Your Structure
// components/index.js /** * Component Library Exports π * * UI Components: Button, Modal, Card, Badge, Avatar (the pretty ones) * Form Components: Input, TextArea, Select, Checkbox (the data collectors) * Layout Components: Header, Footer, Sidebar, Container (the structure crew) * Utility Components: ErrorBoundary, LoadingSpinner (the problem solvers) * * Pro tip: If you can't find a component, it probably doesn't exist yet. * Or maybe it's hiding in the 'experimental' folder π */ export * from './ui'; export * from './forms'; export * from './layout'; export * from './utils'; 4. Handle Default Exports
// For default exports, you gotta be explicit (JavaScript quirks, am I right?) export { default as HomePage } from './pages/HomePage'; export { default as AboutPage } from './pages/AboutPage'; export { default as ContactPage } from './pages/ContactPage'; export { default as NotFoundPage } from './pages/404'; // The page we never want to see // Then use like a civilized developer: import { HomePage, AboutPage, NotFoundPage } from './pages'; Common Pitfalls to Avoid
1. Circular Dependencies
// β This creates the dreaded circular dependency monster πΉ // components/CoffeeOrder.js import { TeaOrder } from './'; // "I need tea to make coffee" - wait, what? // components/TeaOrder.js import { CoffeeOrder } from './'; // "I need coffee to make tea" - this is getting weird // components/index.js export { CoffeeOrder } from './CoffeeOrder'; export { TeaOrder } from './TeaOrder'; // Result: JavaScript.exe has stopped working 2. Over-Exporting
// β Don't export your dirty laundry export * from './internal/SecretSauce'; export * from './private/EmbarrassingComponent'; export * from './experimental/WhoKnowsIfThisWorks'; // β
Be selective about your public API (like a good bouncer) export { Button } from './ui/Button'; export { Modal } from './ui/Modal'; // SecretSauce stays secret, as it should π€« 3. Deep Nesting
// β Too deep - we're not drilling for oil here import { Button } from './components/ui/interactive/buttons/primary/large/red/glowing'; // β
Keep it reasonable (your future self will thank you) import { Button } from './components'; -----
The wrapper pattern isn't just about cleaner importsβit's about:
Maintainable code that scales with your team
Better developer experience for everyone
Consistent architecture across your application
Easier refactoring when requirements change
This simple pattern has transformed how I approach React architecture. It takes 5 minutes to implement but saves hours of frustration down the road.
Top comments (0)