惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
T
ThreatConnect
SecWiki News
SecWiki News
F
Future of Privacy Forum
AWS News Blog
AWS News Blog
C
Cisco Blogs
A
Arctic Wolf
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
V2EX
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
K
Kaspersky official blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
NISL@THU
NISL@THU
Microsoft Azure Blog
Microsoft Azure Blog
量子位
The Hacker News
The Hacker News
Stack Overflow Blog
Stack Overflow Blog
Security Latest
Security Latest
M
Microsoft Research Blog - Microsoft Research
Google Online Security Blog
Google Online Security Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
InfoQ
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
F
Fox-IT International blog
S
Security @ Cisco Blogs
博客园 - 司徒正美
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Comments on: Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LINUX DO - 最新话题
GbyAI
GbyAI
Project Zero
Project Zero
腾讯CDC
T
Tailwind CSS Blog

DEV Community

¿Cómo optimizar algoritmos en arreglos y listas con la técnica de dos punteros? I scanned 8 popular open source repos with one command. Here's what I found. mcp-probe v1.6.0: Stricter GitHub Actions checks for MCP CI gates How we connect two strangers' webcams fast (and keep the TURN bill small) LLM Agents Are Now Finding Zero-Days: How AI is Autonomously Rewriting the Rules of Vulnerability Research Minimal Code Doesn’t Mean Stable Code How I manage 40+ skills across Claude Code, Codex, and .agents folders Hardening Stealth Browser Fingerprint Integrity and State Persistence Quick Tip: Benchmarking Multimodal APIs in Under 10 Minutes How I Slashed My AI API Bill by 92% in 2026 — A Cost Optimizer's Speed Benchmark Guide How I Slashed My AI API Bill by 95% — A Practical Guide for 2026 A Go outbox library that runs inside your own DB transaction How I Built a Credit Optimizer That Saves 30-75% on AI Agent Costs (Open Architecture) The Missing POP: How I Ported a Yul Contract to Huff by Reading Every Opcode The Moment the Config Parser Became the Bottleneck Churn Tool Stack by Revenue Stage ($5K to $50K+) What I Learned Exploring AI-Generated 3D: A Hands-On Tour of Meshy, Tripo, and Three.js Day 15 - Software Composition Analysis(SCA) Contributing Upstream Instead of Forking: My grape-swagger-rails Story Behind The Badge: How We Built 2,000 Hackable Badges For Temporal Replay Access Control Doesn't Scale Linearly -- Part 3 33x faster than Rust: Why I stopped waiting for my compiler and built my own. I Built My First Production AWS Project as a Career Changer Why Detecting PII Matters More Than Ever JSON Schema in 10 Minutes — Validation, Types & Real Examples Python Tasks How I Started My Cybersecurity Journey as an SQA Engineer 🔐 Why "fancy fonts" in Discord and Instagram bios turn into boxes ☁️ GKE private cluster setup — common mistakes and how to avoid them I Thought a Username Didn’t Matter… Until I Saw How Much People Care About It Claude for Small Business: 382K Day-One Buyer's Guide I Built a Diagnostic Toolkit for PyTorch Because I Was Tired of Guessing Why Models Fail How I Built an AI-Powered Incident RCA Platform with LangGraph and RAG The Paywall Was a Painted Door Sonnet hallucinated. My agent stored it as fact. How React-Style Time-Slicing Keeps UIs Responsive 这个 Princeton 开源项目让 AI 自己修 Bug,19K Stars 但 90% 的人只用了 1% 功能 🔥 SWE-agent's 5 Hidden Uses Nobody Told You About 🔥 Decompiling Serial Number U-36: Python TERCOM Reconstruction, Cryptographic Logistical Forensics, and Swarm Consensus Fault Tolerance Microservices Patterns You Cannot Outrun a Wave I Fired My Entire Node.js Stack — Rust Rebuilt It in 3 Weeks (The Ugly Truth) BoxAgnts Introduction (2) — AI Agent Toolbox Cursor 3 ships parallel AI agents. Here is the multi-agent workflow that actually works. Prisma-7 A Complete Beginners Guide (With Free Cloud Database!) Akses HDD Rumah dari Laptop Kantor Pakai Tailscale + SMB (Tanpa VPN Ribet) Content Pipeline in MonoGame: Why I Don't Use It Debug Log #1 — The Pipeline That Looked Broken Data Structures in JavaScript: When to Use What (2026) BGP Route Flap Damping: A Solution or a New Problem? First look at AWS DevOps Agent The Next Big “Cult App” Probably Isn’t Another Social Media Platform From Template to Production-Shaped: An AI-Native Dev Flow for Go Side Projects Idempotency Keys: The API Pattern That Saves You From Duplicate Payments and Phantom Records Everyone's Building Jarvis. Nobody's Even Close. The Moment the Jaeger Tracer Exhausted Itself and What We Switched To How to Fix Tool-Use Loops in Autonomous Coding Agents Months of self-testing: Citations shine, other features remain unproven. Claude Code for Canary Deployments: How I Ship to 1% of Users Before Breaking Everything Your recurring scraper is re-downloading data that didn't change. Here's the 15-line fix (conditional GET) 20 Years of GPUs in Numbers: How FLOPS & TDP Grew, and Who Led the NVIDIA vs AMD Race (open dataset, 13.5k GPUs) Espressif Reveals CoreBoard and Korvo Dev Kits for ESP32-S31 Composable Abstraction Layer: o pattern que faltava entre Pinia e seus componentes Vue Your GitHub Actions Logs Are Leaking LLM Keys and Your SIEM Isn't Catching It Solving Complex Logic with Claude and Research Papers Building TheEpicBook: A Deep Dive into a Node.js Monolithic Web Application Haber yazilimi, haber scripti, haber sistemi: ayni urun, uc ayri arama niyeti Predicting Blood Glucose Fluctuations: Building a Transformer-based CGM Forecaster with PyTorch & InfluxDB Pre-task hooks: the one-line wire-up that gives your Hono agent shared memory Concurrent writes to a shared agent memory: what we shipped, what we punted on Building a Production Serverless URL Shortener on AWS — 21 Articles, Every Test Run for Real My CKA Cheat Sheet: Commands, Aliases, and Documentation Tricks I Used During the Exam Frontend Engineering Beyond Pixels: The Architecture of Digital Accessibility VLA or IL? A Controlled Dataset for Testing Whether Finetuning Turns Your VLA into a Fancy Imitation Learner Fabric AI Functions Turn GenAI Into a Data Pipeline Step Proximate vs Ultimate: The Bug Is Never Just the Bug The Treasure Hunt Engine That Broke Before the Traffic Did Reset Windows Update: The Definitive MSP Guide to RWU Your Resume Was Never Built for This AI Writes 46% of Code Now: What Snap's Layoffs Mean for Developers in 2026 From Chatbot to Agent — Tool Calling with NVIDIA NIM Fatigue and Fracture Mechanics: Why Parts Break Below Their Yield Strength I built a token-level debugger for comparing two LLMs VCP-Virtual Private Cloud Embedding sing-box in an iOS messenger to bypass Russian DPI (no VPN) Microsoft Copilot just exfiltrated a company's files. The attack was one email. Here's the mechanism. RAG 시스템 실전 구축 (v42) copilot cloud agent is becoming an automation api Cx Dev Log — 2026-04-23 Why Tesla Is Becoming the AI Enterprise Case Study Every Leader Should Understand ORA-00214 오류 원인과 해결 방법 완벽 가이드 SpecAgnt v2.0: The Agent Lifecycle Framework for AI-Native Engineering Optimizing Signal Latency and Weight Allocations in Algorithmic Pipelines SSH Under the Hood: Protocols, Mechanisms, and the Full Technical Story دليل بوابات الدفع للتاجر العربي في 2026 (وكيف تختار المناسبة لمتجرك) Cómo Mi Configuración de Docker Me Salvó de un Ataque de Supply Chain (Y Por Qué la Tuya Debería Hacerlo También) How My Docker Setup Saved Me From a Supply Chain Attack (And Why Yours Should Too) Astro: The epitome of SEO Technical Update I Gave My AI Agent the Ability to Research Before It Writes — Here’s What Changed
Advanced React Patterns I Wish I Knew 5 Years Ago
Shudhanshu R · 2026-05-26 · via DEV Community

Five years of React. Hundreds of components. Dozens of refactors. And the lesson I keep re-learning? How you structure your components matters more than what's inside them.

In this post, I'll walk through four patterns I use regularly in production today — with real examples, their trade-offs, and when not to use them.


1. Compound Components

This is the pattern that changed how I think about component APIs entirely.

The Problem

You're building a <Select> or a <Tabs> component. You start with props:

<Tabs
  items={['Overview', 'Details', 'Reviews']}
  activeIndex={0}
  onSelect={handleSelect}
  renderContent={(index) => <div>{content[index]}</div>}
/>

Enter fullscreen mode Exit fullscreen mode

Two weeks later, a designer wants custom icons in the tab labels. Then someone needs a tab to be disabled. Then a badge count. Before long you have 15 props, a messy renderX prop API, and a component nobody wants to touch.

The Pattern

Compound components let the consumer control structure while the parent manages state:

// Usage — clean, readable, extensible
<Tabs defaultIndex={0}>
  <Tabs.List>
    <Tabs.Tab>Overview</Tabs.Tab>
    <Tabs.Tab disabled>Details <Badge>New</Badge></Tabs.Tab>
    <Tabs.Tab>Reviews</Tabs.Tab>
  </Tabs.List>

  <Tabs.Panels>
    <Tabs.Panel><Overview /></Tabs.Panel>
    <Tabs.Panel><Details /></Tabs.Panel>
    <Tabs.Panel><Reviews /></Tabs.Panel>
  </Tabs.Panels>
</Tabs>

Enter fullscreen mode Exit fullscreen mode

Here's the implementation using Context:

const TabsContext = createContext(null);

function Tabs({ defaultIndex = 0, children }) {
  const [activeIndex, setActiveIndex] = useState(defaultIndex);

  return (
    <TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  );
}

function TabList({ children }) {
  return <div role="tablist" className="tab-list">{children}</div>;
}

function Tab({ children, disabled = false }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  const index = useTabIndex(); // tracks position via cloneElement or Context counter

  return (
    <button
      role="tab"
      aria-selected={activeIndex === index}
      disabled={disabled}
      onClick={() => !disabled && setActiveIndex(index)}
    >
      {children}
    </button>
  );
}

function TabPanels({ children }) {
  return <div className="tab-panels">{children}</div>;
}

function TabPanel({ children }) {
  const { activeIndex } = useContext(TabsContext);
  const index = useTabIndex();

  return activeIndex === index ? <div role="tabpanel">{children}</div> : null;
}

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

Enter fullscreen mode Exit fullscreen mode

Why It Works

  • Zero prop-drilling — Context handles shared state transparently.
  • Fully composable — consumers can put anything inside <Tabs.Tab>.
  • Open for extension, closed for modification — adding a <Tabs.Tab> variant doesn't touch the core. ### When NOT to Use It

Compound components shine for UI components with shared state (Tabs, Accordion, Dropdown, Modal). They're overkill for simple stateless components. Don't reach for this pattern reflexively.


2. The State Reducer Pattern

Kent C. Dodds popularised this one, and once you get it, you'll see the use case everywhere.

The Problem

You've built a polished useToggle hook. Then a consumer says:

"Can we prevent the toggle from turning off if a certain condition is met?"

You could add an allowToggleOff prop. Then they ask for disableOnMax. And now your hook has 6 options covering every edge case someone dreamed up — and your tests look like a horror movie.

The Pattern

Give consumers control over how state transitions happen by accepting a custom reducer:

// The hook
function useToggle({ reducer = toggleReducer } = {}) {
  const [state, dispatch] = useReducer(reducer, { on: false });

  const toggle = () => dispatch({ type: 'TOGGLE' });
  const reset = () => dispatch({ type: 'RESET' });

  return { on: state.on, toggle, reset };
}

// Default reducer — normal behaviour
function toggleReducer(state, action) {
  switch (action.type) {
    case 'TOGGLE': return { on: !state.on };
    case 'RESET':  return { on: false };
    default: throw new Error(`Unhandled action: ${action.type}`);
  }
}

Enter fullscreen mode Exit fullscreen mode

Now a consumer can override specific transitions without touching the hook:

function App() {
  const [timesToggled, setTimesToggled] = useState(0);

  function customReducer(state, action) {
    if (action.type === 'TOGGLE' && timesToggled >= 3) {
      // Prevent toggling after 3 times — no hook changes needed
      return state;
    }
    return toggleReducer(state, action); // Delegate everything else
  }

  const { on, toggle } = useToggle({ reducer: customReducer });

  return (
    <div>
      <p>Toggle is {on ? 'ON' : 'OFF'}</p>
      <p>Times toggled: {timesToggled}</p>
      <button onClick={() => { toggle(); setTimesToggled(c => c + 1); }}>
        Toggle
      </button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Why It Works

  • Inversion of control — the hook owns what can happen; the consumer controls when.
  • No breaking changes — adding new behaviour doesn't change the hook's public API.
  • Testable in isolation — you can test the default reducer separately from custom overrides. ### Real Production Use Case

I used this in a form library to let consumers block submission during async validation, throttle re-renders on fast inputs, or add optimistic updates — all without forking the core hook.


3. Headless Components (a.k.a. Renderless Components)

This is the pattern behind Radix UI, Headless UI, and React Aria. And once you use it, you'll never go back to shipping styled components in a shared library.

The Problem

Your design system ships a <Dropdown> component. Works great. Then a team needs a dark-mode version. Then mobile needs a full-screen overlay instead of a floating menu. Now you're maintaining three variants of the same logic — open/close state, keyboard navigation, accessibility roles — duplicated across all three.

The Pattern

Separate behaviour and accessibility from visual rendering:

// Headless hook — pure logic, zero opinions on markup
function useDropdown(items) {
  const [isOpen, setIsOpen] = useState(false);
  const [activeIndex, setActiveIndex] = useState(-1);
  const triggerRef = useRef(null);
  const listRef = useRef(null);

  const open  = () => setIsOpen(true);
  const close = () => { setIsOpen(false); setActiveIndex(-1); };
  const toggle = () => (isOpen ? close() : open());

  const handleKeyDown = (e) => {
    if (!isOpen) return;
    if (e.key === 'ArrowDown') setActiveIndex(i => Math.min(i + 1, items.length - 1));
    if (e.key === 'ArrowUp')   setActiveIndex(i => Math.max(i - 1, 0));
    if (e.key === 'Escape')    close();
    if (e.key === 'Enter' && activeIndex >= 0) {
      items[activeIndex].onSelect();
      close();
    }
  };

  // Returns prop getters — the key to this pattern
  return {
    isOpen,
    activeIndex,
    getTriggerProps: () => ({
      ref: triggerRef,
      onClick: toggle,
      'aria-haspopup': 'listbox',
      'aria-expanded': isOpen,
    }),
    getMenuProps: () => ({
      ref: listRef,
      role: 'listbox',
      onKeyDown: handleKeyDown,
    }),
    getItemProps: (index) => ({
      role: 'option',
      'aria-selected': index === activeIndex,
      onClick: () => { items[index].onSelect(); close(); },
    }),
  };
}

Enter fullscreen mode Exit fullscreen mode

Now any team can render their own markup with full keyboard support and ARIA:

// Team A — desktop floating menu
function DesktopDropdown({ items, label }) {
  const { isOpen, getTriggerProps, getMenuProps, getItemProps } = useDropdown(items);

  return (
    <div className="dropdown">
      <button {...getTriggerProps()}>{label}</button>
      {isOpen && (
        <ul className="dropdown-menu" {...getMenuProps()}>
          {items.map((item, i) => (
            <li key={item.id} className="dropdown-item" {...getItemProps(i)}>
              {item.label}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

// Team B — mobile bottom sheet, same hook
function MobileDropdown({ items, label }) {
  const { isOpen, getTriggerProps, getMenuProps, getItemProps } = useDropdown(items);

  return (
    <>
      <button className="mobile-trigger" {...getTriggerProps()}>{label}</button>
      {isOpen && (
        <div className="bottom-sheet">
          <ul {...getMenuProps()}>
            {items.map((item, i) => (
              <li key={item.id} className="sheet-item" {...getItemProps(i)}>
                <span>{item.icon}</span> {item.label}
              </li>
            ))}
          </ul>
        </div>
      )}
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

The Prop Getter Pattern

Notice the getTriggerProps() / getItemProps() approach — this is the secret sauce. Instead of passing individual ARIA props, you return an object the consumer spreads. This means:

  1. You can add new ARIA attributes to the getter without breaking consumers.
  2. Consumers can merge their own handlers: {...getTriggerProps(), onFocus: myHandler}. ### When to Use It

Build headless when: you're building a shared library used across multiple teams or design languages, or when you're wrapping a complex interaction (date pickers, comboboxes, drag-and-drop).

Don't headless-ify everything. A one-off <UserCard> in your app doesn't need this.


4. Composition Over Configuration

This isn't a single pattern — it's a mindset shift that ties everything together.

The Configuration Trap

// This is a configuration component. It will never stop growing.
<DataTable
  data={rows}
  columns={columns}
  sortable
  filterable
  paginated
  pageSize={10}
  onRowClick={handler}
  rowClassName={(row) => row.urgent ? 'urgent' : ''}
  emptyState={<EmptyIllustration />}
  headerRenderer={(col) => <Tooltip title={col.hint}>{col.label}</Tooltip>}
  footerRenderer={() => <ExportButton />}
  // ...and it keeps going
/>

Enter fullscreen mode Exit fullscreen mode

Every new requirement becomes a new prop. The component's internals become a maze of conditionals. Onboarding a new engineer? Good luck.

The Composition Alternative

<Table>
  <Table.Header>
    {columns.map(col => (
      <Table.Column key={col.id} sortable={col.sortable}>
        <Tooltip title={col.hint}>{col.label}</Tooltip>
      </Table.Column>
    ))}
  </Table.Header>

  <Table.Body data={rows}>
    {(row) => (
      <Table.Row key={row.id} onClick={() => handleRowClick(row)} className={row.urgent ? 'urgent' : ''}>
        {columns.map(col => (
          <Table.Cell key={col.id}>{col.render(row)}</Table.Cell>
        ))}
      </Table.Row>
    )}
  </Table.Body>

  <Table.Footer>
    <Pagination total={total} pageSize={10} onChange={setPage} />
    <ExportButton data={rows} />
  </Table.Footer>
</Table>

Enter fullscreen mode Exit fullscreen mode

More verbose? Yes. But:

  • Adding a sticky footer doesn't require a stickyFooter prop.
  • Custom row grouping doesn't require a groupBy API.
  • Every piece is individually testable. ### The Rule of Thumb

If you catch yourself adding more than 3 render props or 5 boolean flags to a component, it's time to decompose. Composition is usually the answer.


Putting It All Together

These four patterns aren't independent — they complement each other:

Pattern Best For Core Trade-off
Compound Components Shared-state UI (Tabs, Accordion) More verbose usage, but infinitely composable
State Reducer Custom hooks with complex state logic Requires consumers to understand reducer shape
Headless Components Shared libraries across design systems More code up-front; massive long-term flexibility
Composition Any component that's growing too many props Verbose JSX; worth it at scale

None of these are silver bullets. The best engineers I've worked with aren't the ones who know the most patterns — they're the ones who know when patterns are the wrong tool and keep things simple.

But when your component starts growing a config API that rivals a webpack config? That's your signal. Reach for these.


Thanks for reading. If you found this useful, I write about real-world React architecture, performance, and engineering trade-offs. Drop a comment if you've used any of these patterns — or if you've been burned by them. Both stories are worth hearing.