Zustand is probably the most natural default for many modern React apps now.
That makes sense.
It is small, ergonomic, easy to teach, and dramatically less annoying than the old Redux-first mindset.
But after building more AI-heavy frontends, I have a growing suspicion:
Zustand is excellent for getting started, but AI product UIs expose its scaling limits earlier than most teams expect.
This is exactly why I started reaching for easy-model more often.
The Context: Modern React Usually Starts With Zustand
For a lot of teams, the default conversation is no longer:
"Redux or not?"
It is:
"Do we even need more than Zustand?"
For CRUD pages, dashboards, and lightweight shared UI state, that is often the right answer.
But AI frontends are not normal dashboards.
They tend to combine:
- conversation history
- streaming output
- tool execution state
- retries and failure branches
- logs and traces
- cross-panel synchronization
- session scoping
- derived execution context
That is not just "more state." It is state with behavior, process, and lifecycle.
The Hidden Cost of a Very Easy Store
Zustand feels great because almost anything can start simple:
const useChatStore = create(set => ({
messages: [],
streamingText: '',
isStreaming: false,
addMessage: message =>
set(state => ({ messages: [...state.messages, message] })),
setStreamingText: text => set({ streamingText: text }),
}));
This is exactly why people love it.
But the same flexibility can become a trap in AI-heavy apps.
As requirements grow, the store often becomes the path of least resistance for everything:
- state
- business actions
- async requests
- retries
- logs
- context management
- side-effect coordination
Then it quietly turns into this:
const useChatStore = create((set, get) => ({
messages: [],
streamingText: '',
isStreaming: false,
toolCalls: [],
logs: [],
retries: 0,
contextWindow: [],
memory: [],
activeSessionId: '',
addMessage: () => {},
appendStreaming: () => {},
startToolCall: async () => {},
completeToolCall: () => {},
retry: async () => {},
rebuildContext: () => {},
fetchHistory: async () => {},
hydrateSession: async () => {},
}));
Still workable. Still shippable.
But no longer especially clear.
AI Coding Assistants Make This Worse
This is the part people do not talk about enough.
When AI coding tools work inside a growing Zustand codebase, they tend to do one of two things:
- keep adding more logic to the existing store
- start leaking new logic into helper hooks and utility files
Both are understandable.
Neither is ideal.
That is because Zustand optimizes for low-friction authoring, not necessarily for high-clarity continuation by an AI assistant over many iterations.
And that difference matters now.
Why easy-model Feels Better Here
easy-model pushes state into explicit model classes:
- fields represent state
- methods represent business actions
- model instances can be shared naturally in React
For AI-heavy frontends, that is a big deal.
A session becomes a model, not an ever-expanding store:
class AgentSessionModel {
messages: Message[] = [];
streamingText = '';
status: 'idle' | 'running' | 'streaming' = 'idle';
toolCalls: ToolCall[] = [];
logs: string[] = [];
@loader.load(true)
async run(input: string) {
this.status = 'running';
this.messages.push({ role: 'user', content: input });
const stream = await agent.run(this.messages);
this.status = 'streaming';
for await (const chunk of stream) {
this.streamingText += chunk;
}
this.messages.push({
role: 'assistant',
content: this.streamingText,
});
this.streamingText = '';
this.status = 'idle';
}
}
That model has a visible boundary.
It tells both humans and AI tools:
- what this unit owns
- where new behavior belongs
- what state the UI depends on
That clarity becomes extremely valuable once the feature starts changing every week.
This Is Not "Zustand Bad, easy-model Good"
I do not think that is a serious argument.
My actual take is more practical:
- Zustand is fantastic for low-friction shared state
- easy-model is stronger when the frontend starts looking like an application runtime
That happens surprisingly often in AI products.
Especially when you also want:
- shared instances by session or workspace
- richer async coordination
- watchable state transitions
- clearer business boundaries
- code that AI assistants can continue without drifting
The Real Comparison in 2026
The old comparison was:
- Redux vs everything
The more relevant comparison now is often:
- Zustand for speed
- easy-model for structure under complexity
Redux still exists as the historical baseline, but for many modern React teams, Zustand is the real competitor.
And I think easy-model earns its place in that conversation.
Final Thought
If your app is mostly lightweight UI state, Zustand is still hard to beat.
If your app is an AI workspace, agent console, or chat product that keeps accumulating process-heavy behavior, I would not default to Zustand without thinking harder about long-term shape.
That is where easy-model has been surprisingly compelling for me.
GitHub: https://github.com/ZYF93/easy-model
npm: pnpm add @e7w/easy-model
If you are also building AI-heavy React apps, give the repo a star. I think tools optimized for human + AI collaboration are going to become much more important.
Top comments (0)