AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

React Patterns

skill-shiven0504-claude-skills-collection-react-patterns · by Shiven0504

Guide React component architecture — composition patterns, custom hooks, props design, state management, and error boundaries. Use this skill whenever the user is designing React components, refactoring component structure, creating custom hooks, deciding how to manage state, working with context providers, building form components, or asking about React best practices and patterns. Also trigger…

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

Install

$ agentstack add skill-shiven0504-claude-skills-collection-react-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 No
  • 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-shiven0504-claude-skills-collection-react-patterns)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
6mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of React Patterns? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

React Component Patterns

Help users write well-structured React components with clean composition, proper state management, and maintainable patterns. Assumes Next.js + Tailwind CSS environment.

Component Composition

Prefer composition over props overload

Instead of a component with many conditional props, compose smaller focused components together.

Avoid — prop-heavy monolith:

Export}
  footer={View details}
/>

Prefer — composable parts:


  
    Revenue
    Monthly
    Export
  
  
    
  
  
    View details
  

Compound Components

Use compound components when a group of components share implicit state and always work together (tabs, accordions, selects, menus).

"use client"
import { createContext, useContext, useState, type ReactNode } from 'react'

type TabsContextType = { activeTab: string; setActiveTab: (id: string) => void }
const TabsContext = createContext(null)

function useTabs() {
  const ctx = useContext(TabsContext)
  if (!ctx) throw new Error('Tab components must be used within ')
  return ctx
}

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

function TabList({ children }: { children: ReactNode }) {
  return {children}
}

function Tab({ id, children }: { id: string; children: ReactNode }) {
  const { activeTab, setActiveTab } = useTabs()
  return (
     setActiveTab(id)}
      className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${
        activeTab === id
          ? 'border-blue-600 text-blue-600'
          : 'border-transparent text-gray-500 hover:text-gray-700'
      }`}
    >
      {children}
    
  )
}

function TabPanel({ id, children }: { id: string; children: ReactNode }) {
  const { activeTab } = useTabs()
  if (activeTab !== id) return null
  return {children}
}

Tabs.List = TabList
Tabs.Tab = Tab
Tabs.Panel = TabPanel

export { Tabs }

Usage:


  
    Overview
    Analytics
  
  Overview content
  Analytics content

Props Design

Keep props interfaces focused

Each component should accept only the props it needs. Use TypeScript to be explicit:

interface UserCardProps {
  name: string
  email: string
  avatarUrl?: string
  role: 'admin' | 'member' | 'viewer'
}

export function UserCard({ name, email, avatarUrl, role }: UserCardProps) {
  // ...
}

Spread HTML attributes for wrapper components

For components that wrap native elements, extend the native element's props:

import { type ButtonHTMLAttributes, forwardRef } from 'react'

interface ButtonProps extends ButtonHTMLAttributes {
  variant?: 'primary' | 'secondary' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
}

const Button = forwardRef(
  ({ variant = 'primary', size = 'md', className, children, ...props }, ref) => {
    const base = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors'
    const variants = {
      primary: 'bg-blue-600 text-white hover:bg-blue-700',
      secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
      ghost: 'text-gray-600 hover:bg-gray-100',
    }
    const sizes = {
      sm: 'px-3 py-1.5 text-sm',
      md: 'px-4 py-2 text-sm',
      lg: 'px-6 py-3 text-base',
    }

    return (
      
        {children}
      
    )
  }
)
Button.displayName = 'Button'
export { Button }

children vs render props

  • Use children for most cases — it's simpler and more readable.
  • Use render props (or render function children) when the child needs data from the parent:

  {({ data, isLoading }) =>
    isLoading ?  : 
  }

Custom Hooks

Extract logic, not JSX

Custom hooks should encapsulate stateful logic and side effects, returning values and callbacks — not components.

function useDebounce(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value)

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay)
    return () => clearTimeout(timer)
  }, [value, delay])

  return debouncedValue
}
function useLocalStorage(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState(() => {
    if (typeof window === 'undefined') return initialValue
    try {
      const item = window.localStorage.getItem(key)
      return item ? JSON.parse(item) : initialValue
    } catch {
      return initialValue
    }
  })

  const setValue = (value: T | ((val: T) => T)) => {
    const valueToStore = value instanceof Function ? value(storedValue) : value
    setStoredValue(valueToStore)
    window.localStorage.setItem(key, JSON.stringify(valueToStore))
  }

  return [storedValue, setValue] as const
}

Hook naming conventions

  • Always prefix with use
  • Name should describe what data/behavior it provides: useAuth, useMediaQuery, useClickOutside
  • Return consistent shapes: [value, setter] for simple state, { data, error, isLoading } for async

State Management

Start simple, scale as needed

  1. Local state (useState) — for state that belongs to one component
  2. Lifted state — when a sibling needs access, lift to the nearest common parent
  3. Context — for state shared across a subtree (theme, auth, locale)
  4. URL state (searchParams) — for state that should be shareable/bookmarkable (filters, pagination, tabs)
  5. External store (Zustand, Jotai) — for complex client-side state shared across many components

Context — avoid the "god provider" anti-pattern

Split contexts by domain rather than creating one massive AppContext:

// Separate concerns into focused providers

  
    
      {children}
    
  

Each provider manages its own slice of state. Components only subscribe to the contexts they need, which avoids unnecessary re-renders.

URL state for user-facing state

Filters, sort order, pagination, and active tabs should live in the URL so users can share and bookmark views:

"use client"
import { useSearchParams, useRouter, usePathname } from 'next/navigation'

function useQueryState(key: string, defaultValue: string) {
  const searchParams = useSearchParams()
  const router = useRouter()
  const pathname = usePathname()

  const value = searchParams.get(key) ?? defaultValue

  const setValue = (newValue: string) => {
    const params = new URLSearchParams(searchParams.toString())
    if (newValue === defaultValue) {
      params.delete(key)
    } else {
      params.set(key, newValue)
    }
    router.replace(`${pathname}?${params.toString()}`)
  }

  return [value, setValue] as const
}

Controlled vs Uncontrolled Components

Support both patterns

Build form components that work controlled (parent owns the state) or uncontrolled (component owns its own state via defaultValue):

interface InputProps extends Omit, 'size'> {
  label: string
  error?: string
}

export function Input({ label, error, id, ...props }: InputProps) {
  const inputId = id ?? label.toLowerCase().replace(/\s+/g, '-')
  return (
    
      
        {label}
      
      
      {error && {error}}
    
  )
}

Works both ways:

// Controlled
 setEmail(e.target.value)} />

// Uncontrolled

Error Boundaries

Wrap sections, not the entire app

Place error boundaries around independent sections so a failure in one area doesn't crash everything:

"use client"
import { Component, type ReactNode } from 'react'

interface Props {
  children: ReactNode
  fallback?: ReactNode
}

interface State {
  hasError: boolean
  error: Error | null
}

export class ErrorBoundary extends Component {
  state: State = { hasError: false, error: null }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error }
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback ?? (
        
          Something went wrong
          {this.state.error?.message}
        
      )
    }
    return this.props.children
  }
}

Usage:


  }>
    
  
  }>
    
  

Lists and Keys

Use stable, unique identifiers as keys

// Good — stable ID from data
{users.map(user => )}

// Avoid — index as key (breaks with reordering, insertion, deletion)
{users.map((user, i) => )}

Index keys are acceptable only for static lists that never change order.

Conditional Rendering

Keep it readable

// Simple boolean — use &&
{isAdmin && }

// Binary choice — use ternary
{isLoading ?  : }

// Multiple conditions — use early returns or a mapping
function StatusBadge({ status }: { status: 'active' | 'pending' | 'inactive' }) {
  const styles = {
    active: 'bg-green-100 text-green-800',
    pending: 'bg-yellow-100 text-yellow-800',
    inactive: 'bg-gray-100 text-gray-800',
  }

  return (
    
      {status}
    
  )
}

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.