前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redux你是个好人,只是我们不合适

Redux你是个好人,只是我们不合适

作者头像
viktor
发布2022-09-19 19:42:45
5100
发布2022-09-19 19:42:45
举报
文章被收录于专栏:程序员自习室

关注 ▲1分钟前端▲ 和百万前端精英,一起向上生长

当聊到React状态管理方案,很多人第一反应是Redux

Redux为什么这么有名,个人观点,2个原因:

  1. 出现时间早,当时社区还没有更好的状态管理解决方案
  2. React核心团队光环加持。Redux的作者「Dan」开发初版Redux后便加入React团队。另一位联合作者「Andrew」也来自React核心团队

Dan

合适的出现时机加上大名气,催生Redux相关生态在社区快速发展,成为很多前端团队标配。

当谈论状态管理时,通常在谈什么

当谈论「状态管理」时,一般会从「广度」「深度」两个方面来。

广度上,在其之后涌现的解决方案,似乎都在对标Redux,提出自己独到的解决方案。比如:

  • 对标Redux的单向数据流,Mobx使用双向数据绑定
  • 对标Redux「全局状态」理念,recoil提出「原子状态」理念

深度上,Redux社区不断拓展,涌现了基于Redux的中间件,比如Redux-Saga

在中间件之上,又涌现了更全面的解决方案,比如基于Redux-SagaDVA

除了这两个纬度,还有其他视角么?

其实,我们可以从问题的本质出发。

前端,需要哪些状态?

从页面交互角度看,状态来源分为两种:

  • IO操作缓存的数据
  • 用户交互的中间状态

IO操作缓存的数据

前端最常见的IO操作是从服务端请求数据。

如果没使用「状态管理」方案,常见方式是请求数据后保存在组件state中,如:

代码语言:javascript
复制
function App() {
  const [data, updateData] = useState(null);
  
  useEffect(() => {
    fetchData('/api/user').then(data => updateData(data))
  }, [])

  // 处理data
}

当使用「状态管理」方案如Redux,会将请求的数据序列化后保存在「全局状态」中。

用户交互的中间状态

交互的中间状态,比如isLoadingisOpen,同样保存在组件内部。

当可复用组件、或状态需要跨组件层级传递,通常使用Context API

再大范围的状态会使用「状态管理」方案。

可以看到,不管对于「IO操作缓存的数据」还是「用户交互的中间状态」,常规方案是:一视同仁。

这就又回到了讨论「广度」(使用哪种状态)与「深度」(多深入的使用这种状态管理方案)。

但事实上,这两种状态的特性是不同的。

处理缓存的状态管理

对于第一种情况,不管是服务端请求、localStorageindexedDB,本质上说,都可以归类为缓存

所以,相比Redux等常规状态管理方案,缓存处理方案可能更合适。

对于缓存,常见的需求是:

  • 数据状态,加载中?加载完成?发生错误?
  • 缓存失效后的更新
  • 复用缓存数据

React技术栈,SWRreact-query都是优秀的解决方案。这里以SWR举例:

对于刚才的例子:

代码语言:javascript
复制
function App() {
  const [data, updateData] = useState(null);
  
  useEffect(() => {
    fetchData('/api/user').then(data => updateData(data))
  }, [])

  // 处理data
}

SWR使用一个useSWR解决:

代码语言:javascript
复制
function App() {
  const { data, error } = useSWR('/api/user', fetcher)
  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

让我们来看SWR如何满足如上三个需求:

  • 数据状态:通过useSWR的返回值参数判断请求状态。比如!error && !data代表「请求中」
  • 缓存失效后的更新:SWR本身是stale-while-revalidate缩写,一种基于RFC 5861[1]的缓存更新策略。
  • 复用缓存数据:SWR会以请求urlkey,请求对应promisevalue缓存数据,达到多个重复请求复用缓存的目的。

处理用户交互的状态管理

对于「用户交互」产生的状态管理需求,比如:全局modal的开关状态,页面皮肤切换。

我们可以按项目类型、复杂度选择合适的状态管理方案。

横向来看,不同类型项目适合不同状态管理:

  • 前端逻辑很重的工具类项目(比如富文本编辑器),需要完备的redoondo逻辑,Redux「单向不可变数据流」是不二的选择。
  • 后台管理系统,逻辑不复杂,但是繁琐。则Mobx「双向数据绑定」开发效率可能更高。

纵向来看,我们需要考量项目的复杂度:

类似官网、逻辑不复杂的SPA、个人项目,「完全没必要」使用额外的状态管理方案。原生Context API是你最佳的选择。

需要小团队合作的项目,复杂度不高的情况下,Context API就能满足全部需要,只不过需要一点点写法上的规范约束团队同学。这时候可以选择Unstated[2]

Unstated核心代码只有40行,为项目带来规范的状态管理约束的同时不会引入额外的学习成本

只有对于更复杂的项目,才应该考虑ReduxMobx这类解决方案。

总结

对于「状态管理」方案的选择,我们可以遵循如下原则选择:

  1. 区分「缓存」「用户交互」对应的状态,区别对待
  2. 对于「用户交互」的状态,根据项目类型、复杂度选择合适方案

Redux虽好,可不要滥用哦~

参考资料

[1]

RFC 5861: https://tools.ietf.org/html/rfc5861

[2]

Unstated: https://github.com/jamiebuilds/unstated

end

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员自习室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 当谈论状态管理时,通常在谈什么
  • 前端,需要哪些状态?
    • IO操作缓存的数据
      • 用户交互的中间状态
      • 处理缓存的状态管理
      • 处理用户交互的状态管理
      • 总结
        • 参考资料
        相关产品与服务
        消息队列 TDMQ
        消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档