AgentStack
SKILL verified MIT Self-run

Component Patterns

skill-armanzeroeight-fastagent-plugins-component-patterns · by armanzeroeight

Implement React component patterns including composition, custom hooks, render props, HOCs, and compound components. Use when building reusable React components, implementing design patterns, or refactoring component architecture.

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-armanzeroeight-fastagent-plugins-component-patterns

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Component Patterns? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Component Patterns

Implement React component patterns for building reusable, maintainable components.

Quick Start

Use composition for most cases, custom hooks for shared logic, and compound components for flexible APIs.

Instructions

Composition Pattern

The default pattern for building flexible components.

Basic composition:

function Card({ children }) {
  return {children};
}

function CardHeader({ children }) {
  return {children};
}

function CardBody({ children }) {
  return {children};
}

// Usage

  Title
  Content

With props:

interface ButtonProps {
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
  children: React.ReactNode;
}

function Button({ variant = 'primary', size = 'md', children }: ButtonProps) {
  return (
    
      {children}
    
  );
}

Custom Hooks Pattern

Extract and reuse stateful logic across components.

Basic custom hook:

function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  
  const toggle = useCallback(() => {
    setValue(v => !v);
  }, []);
  
  return [value, toggle] as const;
}

// Usage
function Component() {
  const [isOpen, toggleOpen] = useToggle();
  return {isOpen ? 'Close' : 'Open'};
}

Data fetching hook:

function useFetch(url: string) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [url]);
  
  return { data, loading, error };
}

Form hook:

function useForm(initialValues: T) {
  const [values, setValues] = useState(initialValues);
  
  const handleChange = (e: React.ChangeEvent) => {
    setValues(prev => ({
      ...prev,
      [e.target.name]: e.target.value
    }));
  };
  
  const reset = () => setValues(initialValues);
  
  return { values, handleChange, reset };
}

Compound Components Pattern

Create flexible component APIs with implicit state sharing.

Basic compound component:

interface TabsContextValue {
  activeTab: string;
  setActiveTab: (tab: string) => void;
}

const TabsContext = createContext(null);

function Tabs({ children, defaultTab }: { children: React.ReactNode; defaultTab: string }) {
  const [activeTab, setActiveTab] = useState(defaultTab);
  
  return (
    
      {children}
    
  );
}

function TabList({ children }: { children: React.ReactNode }) {
  return {children};
}

function Tab({ id, children }: { id: string; children: React.ReactNode }) {
  const context = useContext(TabsContext);
  if (!context) throw new Error('Tab must be used within Tabs');
  
  const { activeTab, setActiveTab } = context;
  
  return (
     setActiveTab(id)}
    >
      {children}
    
  );
}

function TabPanel({ id, children }: { id: string; children: React.ReactNode }) {
  const context = useContext(TabsContext);
  if (!context) throw new Error('TabPanel must be used within Tabs');
  
  if (context.activeTab !== id) return null;
  return {children};
}

// Attach sub-components
Tabs.List = TabList;
Tabs.Tab = Tab;
Tabs.Panel = TabPanel;

// Usage

  
    Home
    Profile
  
  Home content
  Profile content

Render Props Pattern

Provide render flexibility through function props.

Basic render prop:

interface MouseTrackerProps {
  render: (position: { x: number; y: number }) => React.ReactNode;
}

function MouseTracker({ render }: MouseTrackerProps) {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  
  useEffect(() => {
    const handleMove = (e: MouseEvent) => {
      setPosition({ x: e.clientX, y: e.clientY });
    };
    
    window.addEventListener('mousemove', handleMove);
    return () => window.removeEventListener('mousemove', handleMove);
  }, []);
  
  return <>{render(position)};
}

// Usage
 (
    Mouse at {x}, {y}
  )}
/>

Children as function:

interface DataProviderProps {
  url: string;
  children: (data: T | null, loading: boolean) => React.ReactNode;
}

function DataProvider({ url, children }: DataProviderProps) {
  const { data, loading } = useFetch(url);
  return <>{children(data, loading)};
}

// Usage

  {(users, loading) => (
    loading ?  : 
  )}

Higher-Order Component (HOC) Pattern

Wrap components to add functionality (legacy pattern, prefer hooks).

Basic HOC:

function withLoading(
  Component: React.ComponentType
) {
  return function WithLoadingComponent(props: P & { loading: boolean }) {
    const { loading, ...rest } = props;
    
    if (loading) return ;
    return ;
  };
}

// Usage
const UserListWithLoading = withLoading(UserList);

HOC with additional props:

function withAuth(
  Component: React.ComponentType
) {
  return function WithAuthComponent(props: P) {
    const { user, loading } = useAuth();
    
    if (loading) return ;
    if (!user) return ;
    
    return ;
  };
}

Performance Optimization Patterns

React.memo

Prevent unnecessary re-renders of expensive components.

const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  // Expensive rendering logic
  return {/* Complex UI */};
});

// With custom comparison
const MemoizedComponent = React.memo(
  function Component({ user }) {
    return {user.name};
  },
  (prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);

useMemo

Memoize expensive calculations.

function Component({ items }) {
  const sortedItems = useMemo(() => {
    return items.sort((a, b) => a.value - b.value);
  }, [items]);
  
  const total = useMemo(() => {
    return items.reduce((sum, item) => sum + item.price, 0);
  }, [items]);
  
  return {/* Use sortedItems and total */};
}

useCallback

Memoize functions to prevent child re-renders.

function Parent() {
  const [count, setCount] = useState(0);
  
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []);
  
  return ;
}

const MemoizedChild = React.memo(function Child({ onClick }) {
  return Click;
});

Code Splitting

Split code to reduce initial bundle size.

const LazyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    }>
      
    
  );
}

// Route-based splitting
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const Profile = React.lazy(() => import('./pages/Profile'));

  }>
      
    
  } />

Virtual Scrolling

Handle large lists efficiently.

import { useVirtualizer } from '@tanstack/react-virtual';

function VirtualList({ items }) {
  const parentRef = useRef(null);
  
  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
  });
  
  return (
    
      
        {virtualizer.getVirtualItems().map(virtualItem => (
          
            {items[virtualItem.index].name}
          
        ))}
      
    
  );
}

Common Patterns

Container/Presentational Pattern

Separate logic from presentation.

// Presentational component
interface UserListProps {
  users: User[];
  onDelete: (id: string) => void;
}

function UserList({ users, onDelete }: UserListProps) {
  return (
    
      {users.map(user => (
        
          {user.name}
           onDelete(user.id)}>Delete
        
      ))}
    
  );
}

// Container component
function UserListContainer() {
  const { data: users, isLoading } = useQuery(['users'], fetchUsers);
  const deleteMutation = useMutation(deleteUser);
  
  if (isLoading) return ;
  
  return ;
}

Provider Pattern

Share data across component tree.

interface ThemeContextValue {
  theme: 'light' | 'dark';
  toggleTheme: () => void;
}

const ThemeContext = createContext(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = useCallback(() => {
    setTheme(t => t === 'light' ? 'dark' : 'light');
  }, []);
  
  return (
    
      {children}
    
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) throw new Error('useTheme must be used within ThemeProvider');
  return context;
}

Controlled vs Uncontrolled Components

Controlled (recommended):

function ControlledInput() {
  const [value, setValue] = useState('');
  
  return (
     setValue(e.target.value)}
    />
  );
}

Uncontrolled:

function UncontrolledInput() {
  const inputRef = useRef(null);
  
  const handleSubmit = () => {
    console.log(inputRef.current?.value);
  };
  
  return ;
}

Troubleshooting

Unnecessary re-renders:

  • Use React DevTools Profiler to identify
  • Wrap with React.memo
  • Use useMemo/useCallback appropriately
  • Check if state is lifted too high

Props drilling:

  • Use Context API for deeply nested props
  • Consider component composition
  • Extract intermediate components

Stale closures in hooks:

  • Add dependencies to useEffect/useCallback
  • Use functional updates: setState(prev => prev + 1)
  • Use useRef for mutable values

Memory leaks:

  • Clean up subscriptions in useEffect
  • Cancel pending requests on unmount
  • Remove event listeners

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.