[译] 伟大的 Redux 工具包辩论

avatar

原文 dev.to/srmagura/th…

有一天,我在吃午饭时写的一条不经意的评论引发了与Redux维护者之一Mark Erikson的一场意想不到的有趣辩论。

Redux 长期以来一直是管理 React 应用程序中全局状态的首选库。 Mark帮助创建的Redux工具包是一个相对较新的库,旨在成为“官方的,包含电池的工具集,以实现高效的Redux开发”。这篇文章将介绍我对Redux工具包的优点和潜在缺点的看法。

Redux 为什么很棒

  1. 它是没有主见的。Redux 要求您将全局状态放在存储中,并通过reducer和操作来管理该状态。操作是具有 type 属性的简单 JavaScript 对象,而reducer是基于操作将旧状态转换为新状态的纯函数。除此之外,其他一切都取决于您。
  2. 它具有最小的 API 。Redux 只有 5 个顶级导出,其中只有一个 createStore 是必不可少的。
  3. 它用途广泛。是否希望您的存储中仅包含当前用户的 ID?或者您是否希望您的存储跟踪大型企业应用程序中每个实体、页面、小部件和输入的状态?无论您的用例是什么,Redux 及其大型生态系统都能满足您的需求。

Redux 为什么很难

Redux 很难,原因与它很棒的原因相同。

  1. 它是没有主见的。Redux 没有告诉你如何构建应用程序的状态、reducer或操作,所以你必须做出自己的决定。
  2. 它具有最小的 API 。您很快就会意识到,使用 Redux 创建有用的应用程序需要的不仅仅是 createStore 。这方面的一个主要示例是需要从 API 获取数据以响应操作。
  3. 它用途广泛。Redux 可以有许多不同的前端架构,很容易迷失方向。我花了很长时间才弄清楚 Redux 如何适应我正在构建的 React 应用程序。

Redux 工具包的救援

Redux Toolkit 旨在通过提供一种方便且对初学者友好的 Redux 开发方法来消除前两个痛点。其功能包括:

  • createAction — 允许您定义操作创建者,类似于 typesafe-actions 。我是一个TypeScript的顽固分子,所以类型安全是不可协商的。
  • createReducer — 允许您编写没有 switch 语句的reducer。在引擎盖下使用Immer。Immer是惊人的,即使你不打算使用Redux Toolkit,你也应该在你的reducer中使用它。
  • createSlice — 一个强大的助手,允许您一举定义状态切片的reducer和操作。
  • createEntityAdapter — 返回一组预构建的reducer和选择器函数,用于对实体执行 CRUD。
  • RTK Query - 用于在 Redux 存储中获取和缓存服务器状态的库。可以与 React Query 进行比较,后者旨在解决相同的问题,但方式不同。

我对 Redux Toolkit (RTK) API 的看法

总体建议

  • 如果你是Redux的新手,请使用RTK,但不要觉得你需要利用它的所有功能。你可以用 createAction 和 createReducer 做很多事情。
  • 如果您已经在使用 Redux 和 Immer,则没有理由必须切换到 Redux Toolkit。只有在您同意其方法时才使用它。

createAction

这不是一个新想法,但仍然是一个有用的想法。目前,类型安全操作在这方面似乎比 RTK 更强大,因为类型安全操作 getType 函数在 switch reducer中正确地键入 action.payload 。 ActionType 类型的帮助程序也非常好。我希望看到RTK在这个领域能够与类型安全操作相提并论。

createReducer

正如我之前所说,Immer真的很棒。但是 Immer 已经与 switch reducer中正确地键入完美配合,所以我没有看到 createReducer 的巨大好处。

createSlice

我在这里有一些担忧。我喜欢在传统的 Redux 方法中,您将actions与reducer分开定义。这种关注点分离允许您布置用户可以执行的操作,而不会陷入这些操作的实现方式。 createSlice 避免了这种分离,我不确定这是朝着正确方向迈出的一步。

createAsyncThunk

通过将 createAsyncThunk 包含在 Redux 工具包中,Redux 团队使 thunks 成为官方推荐的 Redux 副作用模型。我喜欢 Redux 本身对副作用的无主见,所以我对 thunks 的内置支持有复杂的感觉。

当然,您仍然可以使用其他副作用模型,例如sagas和observables以及Redux Toolkit。我是 Redux Saga 的忠实粉丝,它使 Redux 与您的后端 API 集成变得简单,同时还使您能够编写非常强大的异步流。Sagas 是使用生成器函数和 yield 编写的,这确实需要一些时间来适应。

createEntityAdapter

我担心 createEntityAdapter 可能会导致设计过于以 CRUD 为中心,偏爱基本的 add 、 update 和 remove 操作,而不是为每个实体量身定制的更有意义的描述性操作。我承认我不完全理解这里的用例。如果 createEntityAdapter 可以避免您编写大量重复代码,请务必使用它。

RTK Query

RTK Query实际上是一个单独的库,恰好与Redux Toolkit位于同一个包中。我认为作为一个单独的包会更好,但这只是我的想法。幸运的是,RTK 查询是从单独的入口点导出的,因此如果您不使用它,它将永远不会包含在您的捆绑包中。

RTK 查询对我来说似乎很复杂,但如果我尝试一下,我的观点可能会改变。如果您正在寻找数据获取解决方案,你也应该考虑React Query。我评估了类似的SWR库,但发现它缺少我的团队经常使用的一些特性。

马克对我声称RTK过于固执己见的回应

在这里阅读完整的评论! 总结:

如您所见,所有这些 API 都有一个共同的主题:

这些是人们一直在使用 Redux 做的事情,并且已经在我们的文档中进行了教学。

因为Redux没有包含任何内置的东西,所以人们不得不手动编写这段代码,或者创建自己的抽象。

因此,我们创建了所有这些概念的标准化实现,人们可以根据需要使用,这样人们将来就不必手动编写任何代码。

我在应用程序中使用什么

我最近的4个 React Web 应用程序

这些都是完全用 React 编写的中型单页应用程序。

  • Redux 约占整个应用程序状态的 10%,本地组件状态占另外 90%。我们故意只将 Redux 用于在屏幕之间导航时需要保留在内存中的状态,例如有关当前用户的信息。
  • 无论是使用Redux还是useReducer,我们都用类型安全的action、Immer和switch语句构造了action和reducer。
  • 一个简单的定制 useQuery 钩子用于从后端获取数据。此数据最终处于 Page 组件的本地状态。
  • 有一些Redux Saga支持登录和持久化用户创建的复杂订单草稿的更改。

我的 React Native

此应用必须脱机工作,因此将应用的大部分状态放在 Redux 中是有意义的。

  • Redux Saga 负责与后端 API 的所有交互。这效果很好。当用户从脱机状态返回时,将排队的操作发送到后端有一个非常复杂的过程。
  • 使用redux-persist 持久化整个Redux存储。这对我来说仍然很神奇。
  • 本地组件状态用于窗体。

我的 Next React Web

新项目总是令人兴奋,因为它们让您有机会重新思考您的架构和技术堆栈。展望未来,我们将:

  • 坚持使用类型安全操作和 switch reducers。这是切换到Redux Toolkit的 createAction 和 createReducer 之间的密切联系。更新:RTK团队成功地说服我试一试 createReducer 和 createSlice !
  • 将我们自己开发的 useQuery 替换为 React Query。因此,我们之前放在 Redux 中的一些状态现在将自动存储在 React Query 的缓存中。
  • 继续在一些地方使用 Redux Saga。