96SEO 2026-08-06 06:34 2
按理说,
你接手了一个中型 React 项目。

说到需求不复杂,使用者登录信息要在 Header、Sidebar、个人中心三个地方展示;主题切换要在全局生效,购物车数据要在商品列表和结算页之间共享。
一开始你用 useState + Context,觉得挺优雅。至于两周后你发现,
UserContext.Provider 套在了 App 最外层。接下来在 个组件里写了 useContext——但其中 个组件只用了 user.name每次使用者对象任何字段变化,这 个组件都会重新渲染。addToCart 写在商品列表组件。removeFromCart 写在购物车组件,updateQuantity 写在结算页组件——你得在三个文件之间跳来跳去才能理解完整的逻辑。value 变了所有消费它的组件都会 re‑render,不管你用没用到主题相关的值。You 开始怀疑:状态管理这件事,有没有更简单的做法?说起来,
有。这篇文章要讲的 Zustand,就是那个“更简单的做法”。
——它不是一个重型框架,不需要你学习 action、reducer、dispatch、middleware 这套概念程序。它是 React 的一个状态管理库,主要目标只有一个:让你用最少的代码共享状态.
React 自带的状态管理工具有三个:a useState、useReducer、Context. 它们各自能处理问题。但组合起来管理全局状态时你会遇到这些麻烦:
| useState + Context | useReducer + Context | Zustand | |
|---|---|---|---|
| 是否需要 Provider 包裹?说起来, | 是 | 是 | No |
| Status change triggers all consumers re‑render? | 是 | 是 | No – 按 selector 控制 |
| The logic must be written inside components? | 是 | 是 | No – Store 完全独立 |
| * 包大小对比:Zustand ~1KB;Redux 等常规库>10KB。不过, | |||
The last row is crucial—Zustand only about ~1 KB. It's not a library you need to weigh heavily before introducing;it's small enough to just drop in.
Zustand 用一句话概括:Zustand 让你在 React 组件外部创建一个全局 Store。组件通过 hook 订阅 Store 的部分状态,状态变化时只有订阅了相关字段的组件会 re‑render。其实,
The three keywords:
- 安装 Zustand:
npm install zustand
# or yarn add zustand
# optional: devtools for debugging # npm i zustand/middleware-devtools # etc...
javascript
import { create } from 'zustand';const useStore = create => ({
说到count,0。increment: => set => ),decrement: => set => ),}));Here’s what happens:
-
`create` receives a function whose first argument is `set` – method used to update state.The function returns an object where each field is eir a state value or an updater .
-
`create` returns a **hook** that can be called from any React component.
更新状态
`set` is **only** way to mutate store.
Merge updates
jsx
const useStore = create(set => ({
firstName:'John'。lastName:'Doe',setFirstName:name=>set,}));// calling set results in {firstName:'Jane'。lastName:'Doe'}
Zustand shallowly merges by default – only supplied fields are overwritten.
Functional updates
jsx
const useStore = create(set=>({
说到count,0,increment:=>set),}));When new state depends on previous state,pass a function to `set`.
❌ Direct mutation of state
jsx
increment:=>set(state=>{
state.count+=1;// mutates original object!
return state;// same reference → no change detected
});Zustand decides wher to notify based on reference equality. Returning same object means “no change”.
✅ Return a new object
jsx
increment:=>set);Now reference changes → update propagates.
Replace entire store
jsx
set;// second arg true → replace instead of merge
Useful for resetting e.g.,logout scenario.
Part : Selector 与性能调整
什么是 Selector?
A selector is simply a function that picks part of store:
jsx
const count = useStore;// selector == =>state.count
Selector isn’t just syntactic sugar—it powers Zustand’s **performance optimization**.
During each update Zustand recomputes every component’s selector and shallowly compares old vs new result. If unchanged → component skips re‑render.
---
### Shallow vs reference comparison
If your selector returns an object/array you’ll get new references every time:
jsx
// ❌ always creates new object → always different reference → always re-renders
function UserInfo{
const user=useStore);}
Solution 👉 **useShallow**:
jsx
import { useShallow } from 'zustand/react/shallow';function UserInfo{
const {name,email}=useStore));}
Now only top‑level fields are compared.
#### Choosing comparison strategy
Selector Returns…*
Use…*
Why?
Primitive value
| value compare works out of box
Plain selector
Reference stays same unless value changes
Object / array where fields may change independently
| reference would always differ
'useShallow'
Shallow compare avoids unnecessary renders
Existing reference stored in Store itself
| reference stable
Plain selector
No extra work needed – returning stored ref keeps identity
### Getting latest value without subscribing
Sometimes you just need current snapshot—for analytics or callbacks:
tsx
const currentCount = useStore.getState.count;function handleClick{
const me=useStore.getState.me;sendAnalytics;}
Using `.getState` never creates subscriptions—perfect for side effects that don’t affect UI.
---
### Subscribing outside React
Zustand also exposes `.subscribe` for pure JS listeners:
tsx
// Subscribe whole store:
const unsubAll=useStore.subscribe);// Subscribe specific field:
const unsubCount=useStore.subscribe(
s=>s.count,cnt=>console.log
);Use cases include:
-
Trigger API calls when certain values change.
-
Sync third‑party libs with your global state.
-
Global logging / telemetry.
---
### Transient Updates
For animation loops or mouse tracking you may want **updates without any component re-rendering**:
tsx
const useMouse=create(set=>({
mouse这方面。{x:-1,y:-1},setMouse:p=>set
}));document.addEventListener('mousemove',e=>{
// direct write。no UI updates triggered automatically
useMouse.getState.setMouse;}),function Canvas{
useEffect=>{
const unsub=useMouse.subscribe);说起来,return unsub;},),}
Key point 👉 Don’t let any component *select* `mouse`;let it subscribe manually when needed.
Part : 切片模式
为什么需要拆分?
当你的应用变复杂,一个 Store 会膨胀到几百行代码。这样的问题和把所有 UI 放进同一个文件一样——难以维护、难以测试。
Problem With One Huge Store
\t\t\t\t\t\t\t\t\t
\
---
### Implementing Slices
Create separate slice functions:
// userSlice.js
const createUserSlice==>({
user这方面。null,login:async credentials=>{
const user=await api.login;set,},logout:=>set,});// cartSlice.js
const createCartSlice==>({
cart=。addToCart:item=>set),removeFromCart:id=>set})),});// meSlice.js
const createThemeSlice==>({
从me来看。'light',toggleTheme:=>set(st=>({
me这方面,st.me==='light'?'dark':'light'
}));}),Now combine:
import {create} from 'zustand';export const useStore=create=>({
...createUserSlice。...createCartSlice,...createThemeSlice,});The spread operator merges all slice objects into one final store.
---
#### Slice ↔ Slice communication
If one slice needs anor's data。call `get` inside its actions:
const createCartSlice==>({
cart=,addToCart:item=>{
const user=get.user;if{console.warn;return,}
set);},}),---
#### When NOT to slice
If your entire store fits comfortably within ~200 lines and can be read quickly,slicing adds overhead.
---
#### Over‑engineering warning
I’ve seen stores with only two fields split into ten slices—each file holding one property!That made even simple changes require hopping across multiple files.
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback