React component patterns, best practices, and architecture guidelines
Provides React component patterns, best practices, and architecture guidelines for building well-structured applications.
/plugin marketplace add the-answerai/alphaagent-team/plugin install aai-stack-react@alphaagent-teamThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Patterns for building well-architected React applications.
// Bad: Doing too much
function UserDashboard() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchUsers().then(setUsers).finally(() => setLoading(false))
}, [])
return (
<div>
{loading ? <Spinner /> : users.map(user => (
<div key={user.id}>
<img src={user.avatar} />
<span>{user.name}</span>
<button onClick={() => deleteUser(user.id)}>Delete</button>
</div>
))}
</div>
)
}
// Good: Single responsibility
function UserDashboard() {
const { users, loading } = useUsers()
if (loading) return <Spinner />
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
)
}
// Container: Handles data and logic
function UserListContainer() {
const { users, loading, error, deleteUser } = useUsers()
return (
<UserList
users={users}
loading={loading}
error={error}
onDelete={deleteUser}
/>
)
}
// Presenter: Handles rendering
interface UserListProps {
users: User[]
loading: boolean
error?: Error
onDelete: (id: string) => void
}
function UserList({ users, loading, error, onDelete }: UserListProps) {
if (loading) return <Spinner />
if (error) return <ErrorMessage error={error} />
return (
<ul>
{users.map(user => (
<UserItem key={user.id} user={user} onDelete={onDelete} />
))}
</ul>
)
}
// Compound component pattern for flexible composition
interface TabsContextValue {
activeTab: string
setActiveTab: (tab: string) => void
}
const TabsContext = createContext<TabsContextValue | null>(null)
function Tabs({ children, defaultTab }: { children: ReactNode; defaultTab: string }) {
const [activeTab, setActiveTab] = useState(defaultTab)
return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
)
}
Tabs.List = function TabList({ children }: { children: ReactNode }) {
return <div className="tab-list">{children}</div>
}
Tabs.Tab = function Tab({ id, children }: { id: string; children: ReactNode }) {
const { activeTab, setActiveTab } = useContext(TabsContext)!
return (
<button
className={activeTab === id ? 'active' : ''}
onClick={() => setActiveTab(id)}
>
{children}
</button>
)
}
Tabs.Panel = function TabPanel({ id, children }: { id: string; children: ReactNode }) {
const { activeTab } = useContext(TabsContext)!
if (activeTab !== id) return null
return <div className="tab-panel">{children}</div>
}
// Usage
<Tabs defaultTab="profile">
<Tabs.List>
<Tabs.Tab id="profile">Profile</Tabs.Tab>
<Tabs.Tab id="settings">Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel id="profile">Profile content</Tabs.Panel>
<Tabs.Panel id="settings">Settings content</Tabs.Panel>
</Tabs>
interface MousePosition {
x: number
y: number
}
interface MouseTrackerProps {
render: (position: MousePosition) => ReactNode
}
function MouseTracker({ render }: MouseTrackerProps) {
const [position, setPosition] = useState<MousePosition>({ x: 0, y: 0 })
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('mousemove', handleMouseMove)
return () => window.removeEventListener('mousemove', handleMouseMove)
}, [])
return <>{render(position)}</>
}
// Usage
<MouseTracker
render={({ x, y }) => (
<div>Mouse at: {x}, {y}</div>
)}
/>
// HOC for adding authentication check
function withAuth<P extends object>(
WrappedComponent: ComponentType<P>
) {
return function WithAuthComponent(props: P) {
const { user, loading } = useAuth()
if (loading) return <Spinner />
if (!user) return <Navigate to="/login" />
return <WrappedComponent {...props} />
}
}
// Usage
const ProtectedDashboard = withAuth(Dashboard)
function ControlledInput() {
const [value, setValue] = useState('')
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
)
}
function UncontrolledInput() {
const inputRef = useRef<HTMLInputElement>(null)
const handleSubmit = () => {
console.log(inputRef.current?.value)
}
return (
<>
<input ref={inputRef} defaultValue="" />
<button onClick={handleSubmit}>Submit</button>
</>
)
}
interface InputProps {
value?: string
defaultValue?: string
onChange?: (value: string) => void
}
function FlexibleInput({ value, defaultValue, onChange }: InputProps) {
const [internalValue, setInternalValue] = useState(defaultValue ?? '')
const isControlled = value !== undefined
const currentValue = isControlled ? value : internalValue
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
if (!isControlled) {
setInternalValue(e.target.value)
}
onChange?.(e.target.value)
}
return (
<input value={currentValue} onChange={handleChange} />
)
}
// Memoize expensive computations
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name))
}, [items])
// Memoize callbacks
const handleClick = useCallback((id: string) => {
setSelectedId(id)
}, [])
// Memoize components
const MemoizedList = memo(function List({ items }) {
return items.map(item => <Item key={item.id} {...item} />)
})
// Lazy load components
const HeavyComponent = lazy(() => import('./HeavyComponent'))
function App() {
return (
<Suspense fallback={<Spinner />}>
<HeavyComponent />
</Suspense>
)
}
class ErrorBoundary extends Component<Props, State> {
state = { hasError: false, error: null }
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Error caught:', error, errorInfo)
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? <DefaultErrorFallback />
}
return this.props.children
}
}
// Usage
<ErrorBoundary fallback={<ErrorMessage />}>
<RiskyComponent />
</ErrorBoundary>
Used by:
frontend-developer agentfullstack-developer agentCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.