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

推荐订阅源

T
Tenable Blog
博客园_首页
Vercel News
Vercel News
WordPress大学
WordPress大学
美团技术团队
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Y
Y Combinator Blog
博客园 - 【当耐特】
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
腾讯CDC
M
MIT News - Artificial intelligence
爱范儿
爱范儿
Recent Announcements
Recent Announcements
雷峰网
雷峰网
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
The Register - Security
The Register - Security
Jina AI
Jina AI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
P
Privacy & Cybersecurity Law Blog
Recorded Future
Recorded Future
Help Net Security
Help Net Security
N
News and Events Feed by Topic
博客园 - Franky
P
Proofpoint News Feed
L
LINUX DO - 热门话题
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
D
Docker
Google DeepMind News
Google DeepMind News
有赞技术团队
有赞技术团队
IT之家
IT之家
Security Latest
Security Latest
L
LangChain Blog
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
J
Java Code Geeks

Echo JS

Desktop apps Introducing mermaid-lint: Stop Shipping Broken Diagrams How We Cut Slow Responses by 80% Migrating to Next.js App Router The quiet problem with unnecessary async - Matt Smith GitHub - ant-design/ant-design-cli: Ant Design on your command line. Query component knowledge, analyze project usage, and guide migrations — fully offline. Uncovering the Magic Behind Playwright React Performance Isn’t About useMemo — It’s About Render Boundaries T2 No Escape Hatches · Prickles GitHub - auto-agent-protocol/auto-agent-protocol: Automotive Agent Protocol GitHub - coactionjs/coaction: Zustand-style state management with built-in render tracking and cached computed state GitHub - williamtroup/Rattribute.js: ❓ A lightweight JavaScript library for automatically changing HTML element attributes based on responsive screen sizes. GitHub - williamtroup/Rink.js: 🔗 A JavaScript library for generating responsive HTML link targets. SVAR Kanban: Interactive Task Board Component for Svelte, React, and Vue Performance Cost of Popular 3rd Party Scripts date-light - Tiny date utilities for JavaScript GitHub - jskits/loggerjs: A faster, more powerful isomorphic logger Out Loud — Free AI Text to Speech Pocket DB — Embedded single-file NoSQL for Node.js billboard.js 4.0 release: Canvas rendering mode, 94.3% faster! GitHub - thegruber/linkpeek: Secure TypeScript link preview and URL metadata extractor for Open Graph, Twitter Cards, JSON-LD, Node/Bun/Deno/edge. GitHub - evoluteur/healing-frequencies: Play the healing frequencies of various sets of tuning forks: Solfeggio, Organs, Mineral nutrients, Ohm, Chakras, Cosmic octave, Otto, DNA nucleotides... or custom. Animated sine waves - 27 lines of pure JavaScript Framework | Neutralinojs GitHub - AllThingsSmitty/typescript-tips-everyone-should-know: ✅ A curated collection of practical TypeScript patterns that improve safety, readability, maintainability, and developer experience. 🧠 Heat.js : JavaScript Heat Map GitHub - iDev-Games/State-JS: State.js is a CSS‑reactive framework that makes UI state and updates flow through CSS instead of JavaScript logic. GitHub - yankouskia/gameplate: :video_game: Boilerplate for creating game with WebGL & Redux :game_die: GitHub - yankouskia/get-browser: 💻 Lightweight tool to identify the browser (mobile+desktop detection)📱 GitHub - yankouskia/is-incognito-mode: Identify whether browser is in incognito mode 👀
When React Hooks Stop Scaling: Moving Complex State to Zustand - Oren Farhi
Oren Farhi · 2026-07-09 · via Echo JS

In most of my React work, I reach for hooks first.

They’re usually the simplest way to keep state close to the UI and encapsulate behavior without introducing additional complexity.

Recently, I was building a speech recognition feature that streamed transcripts in real time, tracked whether the user was speaking, and exposed recognition errors to the UI.

The initial implementation lived inside a custom hook.

const {
  transcript,
  error,
  isUserSpeaking
} = useSpeechRecognition();

At first, that worked well.

Then requirements changed.

I needed transcript updates to be visible in multiple parts of the application. Some updates originated from browser speech recognition events, while others came from services outside the component tree.

That’s when things started getting messy.

The Bug That Made Me Reconsider

The first real warning sign wasn’t architectural.

It was a bug.

Users would occasionally see stale transcript data even though speech recognition events were still arriving.

At first I suspected a browser issue.

Then I suspected event ordering.

Then I spent several hours tracing state updates across effects, refs, callbacks, and component re-renders.

The actual problem was that multiple components were depending on the same state, but ownership of that state was still buried inside a hook that had originally been designed for a single UI flow.

Nothing was technically broken.

The design no longer matched the way the feature was being used.

The Hook Was Doing Too Much

I started with a custom hook because it felt like the simplest way to keep the speech recognition logic near the UI.

That worked until the same state needed to be read outside the original component tree and updated from code that didn’t belong to any one screen.

At that point, the hook wasn’t just reusable logic anymore.

It was acting like shared application state.

The hook eventually became responsible for:

  • Managing speech recognition lifecycle
  • Handling browser-specific events
  • Updating transcripts
  • Tracking speaking state
  • Reporting errors
  • Synchronizing data across multiple consumers

The public API still looked simple.

The implementation no longer was.

Why Context Wasn’t Enough

React Context was an option.

I considered it.

The problem wasn’t simply sharing state.

I also needed updates to originate outside React components.

Speech recognition events arrive asynchronously from browser APIs.

Some consumers only cared about transcript updates.

Others only cared about speaking status.

I wanted state updates to happen independently of React component ownership.

That pushed me toward a dedicated store.

Moving the State to Zustand

Instead of keeping everything inside a hook, I moved the state into Zustand.

const useRecognitionStore = create((set) => ({
  transcript: "",
  isUserSpeaking: false,

  setTranscript: (transcript) =>
    set({ transcript }),

  setSpeaking: (isUserSpeaking) =>
    set({ isUserSpeaking })
}));

The speech recognition service updates the store directly:

recognition.onresult = (event) => {
  useRecognitionStore
    .getState()
    .setTranscript(event.results[0][0].transcript);
};

Components subscribe only to the data they need:

const transcript = useRecognitionStore(
  state => state.transcript
);

That small change removed a surprising amount of complexity.

What Actually Improved

The biggest benefit wasn’t performance.

It was removing ambiguity around state ownership.

Before the migration, I regularly had to answer questions like:

  • Which component owns this state?
  • Why isn’t this update visible here?
  • Which effect updates this value?

After moving state into a store, those questions largely disappeared.

Speech recognition events update the store.

Components read from the store.

The flow became easier to follow because there was a single source of truth instead of state being hidden inside a hook implementation.

When I Still Prefer Hooks

I still use hooks extensively.

If state belongs to a component, useState is usually the right solution.

If I’m encapsulating reusable UI behavior, a custom hook is often exactly what I want.

But once state needs to be shared across unrelated parts of an application and updated from external systems, I start treating it as application state rather than component state.

That distinction has become a useful architectural guideline for me.

Final Thoughts

Nothing was wrong with the original hook.

It solved the problem it was originally designed for.

The problem changed.

The moment state became shared across multiple consumers and started receiving updates from outside React, the hook stopped being the right abstraction.

Moving that state into Zustand didn’t reduce complexity.

The complexity was already there.

It simply made the complexity visible and gave it a place to live.

Check out ReadM and try it out just for fun.