Skip to content

状态该放在哪一层? ​

能留在组件里的状态就留在组件里。只有跨层级、而且变化不频繁的数据才放进 Context 或 provide / inject。服务端数据用请求缓存,不要和按钮开关混在同一个全局 store。

原理 ​

本地状态最近:谁渲染谁持有,更新范围最小。两个兄弟要共享时,再把状态抬到最近的共同父组件。

React Context 适合主题、语言、当前用户这种低频数据。Provider 的 value 一变,所有 useContext 的组件都会渲染,中间的 memo 挡不住。高频字段如果和低频字段放在同一个对象里,低频消费者也会被带着渲染。可以拆成多个 Context,或者用带选择器的状态库,让组件只订阅它读到的那一块。

Redux 的模型是单一 store、用 action 描述发生了什么、用 reducer 算出下一个不可变状态。副作用放在 middleware 或 thunk 里,reducer 保持纯函数。Zustand、Pinia 把同样的「可读、可追踪」收成更少的样板。Vue 这边 Pinia 是当前的选择;Vuex 的 mutation 分层在新项目里不再需要。

接口数据会过期、会重试、会被很多页面共用。用 TanStack Query 这类库管理请求缓存、失效和加载状态。全局 store 里只留真正的客户端状态,例如向导走到第几步、侧边栏是否收起。

追问 ​

什么时候引入全局状态库?

出现很多「为了传一个值而存在」的中间组件,或者多块相距很远的 UI 要读写同一份客户端状态时。只为了一个表单,不要上全局库。

Context 性能差,是不是不能用?

低频数据完全适合。痛点是颗粒度:把会每秒变的数据和很少变的数据放进同一个 value。拆开,或者让高频数据走选择器订阅。

易错点 ​

  • 前端 store 里的权限标记不能代替接口鉴权。见 权限控制。
  • 把接口响应原样塞进全局 store,又没有失效策略,页面会一直显示旧数据。
  • 每次渲染都写 value= 会制造新对象,Context 消费者每次都更新。把对象用 useMemo 稳住,或拆开传。

相关 ​