Redux你是个好人,只是我们不合适
Redux你是个好人,只是我们不合适
当聊到 React
状态管理方案,很多人第一反应是 Redux
。
Redux
为什么这么有名,个人观点,2个原因:
- 出现时间早,当时社区还没有更好的状态管理解决方案
- 有
React
核心团队光环加持。Redux
的作者 「Dan」 开发初版Redux
后便加入React
团队。另一位联合作者 「Andrew」 也来自React
核心团队

合适的出现时机加上大名气,催生 Redux
相关生态在社区快速发展,成为很多前端团队标配。
当谈论状态管理时,通常在谈什么
当谈论 「状态管理」 时,一般会从 「广度」 、 「深度」 两个方面来。

广度上,在其之后涌现的解决方案,似乎都在对标 Redux
,提出自己独到的解决方案。比如:
- 对标
Redux
的单向数据流,Mobx
使用双向数据绑定 - 对标
Redux
的 「全局状态」 理念,recoil
提出 「原子状态」 理念
深度上, Redux
社区不断拓展,涌现了基于 Redux
的中间件,比如 Redux-Saga
。
在中间件之上,又涌现了更全面的解决方案,比如基于 Redux-Saga
的 DVA
。
除了这两个纬度,还有其他视角么?
其实,我们可以从问题的本质出发。
前端,需要哪些状态?
从页面交互角度看,状态来源分为两种:
- IO操作缓存的数据
- 用户交互的中间状态
IO操作缓存的数据
前端最常见的IO操作是从服务端请求数据。
如果没使用 「状态管理」 方案,常见方式是请求数据后保存在组件 state
中,如:
function App() { const [data, updateData] = useState(null); useEffect(() => { fetchData('/api/user').then(data => updateData(data)) }, []) // 处理data }
当使用 「状态管理」 方案如 Redux
,会将请求的数据序列化后保存在 「全局状态」 中。
用户交互的中间状态
交互的中间状态,比如 isLoading
、 isOpen
,同样保存在组件内部。
当是可复用组件、或状态需要跨组件层级传递,通常使用 Context API
。
再大范围的状态会使用 「状态管理」 方案。
可以看到,不管对于 「IO操作缓存的数据」 还是 「用户交互的中间状态」 ,常规方案是:一视同仁。
这就又回到了讨论 「广度」 (使用哪种状态)与 「深度」 (多深入的使用这种状态管理方案)。
但事实上,这两种状态的特性是不同的。
处理缓存的状态管理
对于第一种情况,不管是服务端请求、 localStorage
、 indexedDB
,本质上说,都可以归类为 缓存
。
所以,相比 Redux
等常规状态管理方案,缓存处理方案可能更合适。
对于 缓存
,常见的需求是:
- 数据状态,加载中?加载完成?发生错误?
- 缓存失效后的更新
- 复用缓存数据
在 React
技术栈, SWR
、 react-query
都是优秀的解决方案。这里以 SWR
举例:

对于刚才的例子:
function App() { const [data, updateData] = useState(null); useEffect(() => { fetchData('/api/user').then(data => updateData(data)) }, []) // 处理data }
SWR
使用一个 useSWR
解决:
function App() { const { data, error } = useSWR('/api/user', fetcher) if (error) returnfailed to loadif (!data) returnloading...returnhello {data.name}!}
让我们来看 SWR
如何满足如上三个需求:
- 数据状态:通过
useSWR
的返回值参数判断请求状态。比如!error && !data
代表 「请求中」 。 - 缓存失效后的更新:
SWR
本身是stale-while-revalidate
缩写,一种基于RFC 5861的缓存更新策略。 - 复用缓存数据:
SWR
会以请求url
为key
,请求对应promise
为value
缓存数据,达到多个重复请求复用缓存的目的。
处理用户交互的状态管理
对于 「用户交互」 产生的状态管理需求,比如:全局 modal
的开关状态,页面皮肤切换。
我们可以按项目类型、复杂度选择合适的状态管理方案。

横向来看,不同类型项目适合不同状态管理:
- 前端逻辑很重的工具类项目(比如富文本编辑器),需要完备的
redo
、ondo
逻辑,Redux
的 「单向不可变数据流」 是不二的选择。 - 后台管理系统,逻辑不复杂,但是繁琐。则
Mobx
的 「双向数据绑定」 开发效率可能更高。
纵向来看,我们需要考量项目的复杂度:
类似官网、逻辑不复杂的 SPA
、个人项目, 「完全没必要」 使用额外的状态管理方案。原生 Context API
是你最佳的选择。
需要小团队合作的项目,复杂度不高的情况下, Context API
就能满足全部需要,只不过需要一点点写法上的规范约束团队同学。这时候可以选择 Unstated

Unstated
核心代码只有40行,为项目带来规范的状态管理约束的同时不会引入额外的学习成本
只有对于更复杂的项目,才应该考虑 Redux
、 Mobx
这类解决方案。
总结
对于 「状态管理」 方案的选择,我们可以遵循如下原则选择:
- 区分 「缓存」 与 「用户交互」 对应的状态,区别对待
- 对于 「用户交互」 的状态,根据项目类型、复杂度选择合适方案
Redux
虽好,可不要滥用哦~