为啥使用 Redux 而不是 Facebook Flux? [关闭]

Posted

技术标签:

【中文标题】为啥使用 Redux 而不是 Facebook Flux? [关闭]【英文标题】:Why use Redux over Facebook Flux? [closed]为什么使用 Redux 而不是 Facebook Flux? [关闭] 【发布时间】:2015-12-04 08:11:16 【问题描述】:

我已经阅读了this answer、reducing boilerplate,查看了一些 GitHub 示例,甚至尝试了一些 redux(待办事项应用程序)。

据我了解,official redux doc motivations 提供了与传统 MVC 架构相比的优势。但它没有提供问题的答案:

为什么应该使用 Redux 而不是 Facebook Flux?

这只是编程风格的问题:功能性与非功能性?还是问题出在 redux 方法的能力/开发工具中?也许缩放?还是测试?

如果我说 redux 对于来自函数式语言的人来说是一种变化,我说得对吗?

要回答这个问题,您可以比较 redux 在 Flux 和 redux 上的动机点的实现复杂性。

以下是来自official redux doc motivations 的激励点:

    处理乐观更新(据我了解,这几乎不取决于第 5 点。在 facebook 通量中很难实现它吗?) 在服务器上渲染(facebook Flux 也可以这样做。与 redux 相比有什么好处吗?) 在执行路由转换之前获取数据(为什么不能在 facebook Flux 中实现?有什么好处?) 热重载(React Hot Reload 可以实现。为什么我们需要 redux?) 撤消/重做功能 还有其他要点吗?像持久化状态...

【问题讨论】:

Redux 是“Facebook Flux”的一个实现。 Flux 不是库或框架。它只是 Web 应用程序的推荐架构。我看不出如何将具体实现与激发它的抽象概念进行比较。 Facebook 实际实现的 Flux 架构是 Relay,开源版本仍处于早期阶段。 facebook.github.io/relay @CharlieMartin 由 FB Flux I ment 申请像这样github.com/facebook/flux/tree/master/examples。我目前的项目是在 FB Flux 上编写的(由于 FB Flux)。如果你愿意,你可以认为 Redux 架构优于 FB Flux 架构。 我现在明白了。您想将 Facebook 的 Flux 实现示例与 Redux 的 Flux 实现进行比较 Relay 不是 Flux 的实现 - Relay/GraphQL 更关心管理与服务器的数据获取/查询,而 Flux 主要关心构建客户端数据模型和视图组件之间的数据流。但是有一些重叠:在 Facebook,我们的应用程序完全使用 Flux、完全使用 Relay 或两者兼而有之。我们看到出现的一种模式是让 Relay 管理应用程序的大部分数据流,但使用 Flux 存储来处理应用程序状态的子集 【参考方案1】:

Redux 作者在这里!

Redux 与 Flux 并没有不同。总体而言,它具有相同的架构,但 Redux 能够通过使用 Flux 使用回调注册的函数组合来减少一些复杂性。

Redux 没有根本区别,但我发现它使某些抽象更容易,或者至少可以实现,而这在 Flux 中很难或不可能实现。

减速机成分

以分页为例。我的Flux + React Router example 处理分页,但代码很糟糕。糟糕的原因之一是 Flux 使得跨商店重用功能变得不自然。如果两个商店需要处理分页以响应不同的操作,它们要么需要从一个共同的基础商店继承(不好! 当您使用继承时,您将自己锁定在特定的设计中),或者从事件处理程序中调用外部定义的函数,这将需要以某种方式对 Flux 存储的私有状态进行操作。整个事情都很混乱(尽管绝对是可能的)。

另一方面,由于 reducer 的组合,Redux 的分页是很自然的。它一直是减速器,所以你可以写一个reducer factory that generates pagination reducers 然后use it in your reducer tree。之所以如此简单,关键在于在 Flux 中,store 是扁平的,但在 Redux 中,reducer 可以通过函数组合嵌套,就像 React 组件可以嵌套一样。

此模式还支持无用户代码undo/redo 等精彩功能。 您能想象将 Undo/Redo 插入 Flux 应用程序是两行代码吗?几乎不。对于 Redux,它是——再次感谢 reducer 组合模式。我需要强调它并没有什么新东西——这是Elm Architecture 中开创并详细描述的模式,它本身就受到了 Flux 的影响。

服务器渲染

人们一直在使用 Flux 在服务器上进行渲染,但是看到我们有 20 个 Flux 库,每个库都试图使服务器渲染“更容易”,也许 Flux 在服务器上有些粗糙的边缘。事实上,Facebook 并没有做太多的服务器渲染,所以他们并没有很关心它,而是依靠生态系统来简化它。

在传统的 Flux 中,商店是单例的。这意味着很难为服务器上的不同请求分离数据。不是不可能,但很难。这就是为什么大多数 Flux 库(以及新的 Flux Utils)现在建议您使用类而不是单例,这样您就可以根据请求实例化存储。

您仍然需要在 Flux 中解决以下问题(您自己或借助您喜欢的 Flux 库,例如 Flummox 或 Alt):

如果存储是类,如何根据请求使用调度程序创建和销毁它们?我什么时候注册商店? 如何对存储中的数据进行水化,然后在客户端对其进行再水化?我需要为此实施特殊方法吗?

诚然,Flux 框架(不是普通的 Flux)可以解决这些问题,但我发现它们过于复杂。例如,Flummox asks you to implement serialize() and deserialize() in your stores。 Alt 通过提供takeSnapshot() 来更好地解决这个问题,它会自动在 JSON 树中序列化您的状态。

Redux 更进一步:因为只有一个 store(由许多 reducer 管理),所以你不需要任何特殊的 API 来管理(重新)水化。你不需要“刷新”或“水合”存储——只有一个存储,您可以读取其当前状态,或创建具有新状态的新存储。每个请求都会获得一个单独的商店实例。 Read more about server rendering with Redux.

同样,这在 Flux 和 Redux 中都是可能的,但是 Flux 库通过引入大量 API 和约定来解决这个问题,而 Redux 甚至不必解决它,因为它没有首先是由于概念上的简单性。

开发者体验

我实际上并不打算让 Redux 成为一个流行的 Flux 库——我是在编写 ReactEurope talk on hot reloading with time travel 时写的。我有一个主要目标:可以通过删除操作来动态更改 reducer 代码,甚至“改变过去”,并查看重新计算的状态。

我还没有看到一个 Flux 库能够做到这一点。 React Hot Loader 也不允许你这样做——事实上,如果你编辑 Flux 存储,它会中断,因为它不知道如何处理它们。

当 Redux 需要重新加载 reducer 代码时,它会调用 replaceReducer(),应用程序会使用新代码运行。在 Flux 中,数据和函数纠缠在 Flux 存储中,所以不能“只替换函数”。此外,您必须以某种方式向 Dispatcher 重新注册新版本——这是 Redux 甚至没有的。

生态系统

Redux 有一个rich and fast-growing ecosystem。这是因为它提供了一些扩展点,例如middleware。它的设计考虑了logging、Promises、Observables、routing、immutability dev checks、persistence 等用例的支持。并非所有这些都会变得有用,但很高兴能够使用一组可以轻松组合以协同工作的工具。

简单

Redux 保留了 Flux 的所有优点(动作的记录和回放、单向数据流、依赖突变)并增加了新的优点(轻松撤消重做、热重新加载),而无需引入 Dispatcher 和存储注册。

保持简单很重要,因为它可以让您在实现更高级别的抽象时保持清醒。

与大多数 Flux 库不同,Redux API 表面很小。如果您删除开发人员警告、cmets 和健全性检查,则为99 lines。无需调试棘手的异步代码。

您实际上可以阅读并理解所有 Redux。


另见my answer on downsides of using Redux compared to Flux。

【讨论】:

感谢您的回答...我是 js 新手...在您的回答中您说 Flux 正在使用单例设计模式...您能在 redux 中告诉我它们是哪种设计模式吗使用......并且不断变化,你能告诉我他们在哪里使用单例模式......你能举一个例子......我从这里理解了设计模式singleton 我基于 Fluxxor(基本上是纯 Flux)开始了我的 android/Java 实现(Fluxxan)。一旦我看到 redux,我就被卖掉了。有些部分我保持不变,但是伙计,你的库太棒了! 你想学习 Redux 吗?只需观看此视频:youtube.com/watch?v=ucd5x3Ka3gw 我们选择 redux 是因为它比 Flux 更固执己见。我们一直在争论某些代码应该如何/在哪里等等。Redux 为我们消除了所有这些困惑。我们已经为 web 和 react-native 构建了带有 redux 的应用程序,这太棒了!! github.com/reactjs/redux/blob/… 行是我搜索了一周的问题的答案:如何构建 store 和 reducers,以便在不重复的情况下处理在不同上下文中使用的多个可重用组件实例逻辑。答案似乎是:使用三层深度存储:第一层:组件名称(“分页”),第二层:容器名称(“stargazersByRepo”),第三层:容器的唯一键/ID( $login/$name)。非常感谢!【参考方案2】:

In Quora, somebody says:

首先,完全可以使用 React 编写应用程序,而无需 通量。

还有我创建的这个可视化图表,用于快速查看两者,对于不想阅读整个解释的人来说,这可能是一个快速的答案:

但如果您仍然有兴趣了解更多信息,请继续阅读。

我认为你应该从纯 React 开始,然后学习 Redux 和 Flux。 在你对 React 有一些真正的体验之后,你会看到 Redux 是否对你有帮助。

也许你会觉得 Redux 完全适合你的应用程序,也许你 会发现,Redux 正在尝试解决你没有解决的问题 真体验。

如果你直接从 Redux 开始,你最终可能会过度设计 代码,代码更难维护,并且有更多的错误,而不是没有 还原。

来自Redux docs:

动机 随着对 javascript 单页应用程序的要求变得越来越复杂,我们的 代码必须管理比以往更多的状态。这种状态可以包括 服务器响应和缓存数据,以及本地创建的数据 尚未持久化到服务器。 UI状态也在增加 在复杂性方面,因为我们需要管理活动路线、选定的选项卡、 微调器、分页控件等。

管理这种不断变化的状态很困难。如果模型可以更新 另一个模型,然后视图可以更新一个模型,该模型更新另一个 模型,而这反过来可能会导致另一个视图更新。在某些 点,您不再像以前那样了解应用程序中发生的事情 失去对其状态的时间、原因和方式的控制。当一个系统 不透明且不确定,很难重现错误或添加 新功能。

好像这还不够糟糕,考虑一下新的要求 常见于前端产品开发。作为开发者,我们 预计将处理乐观更新、服务器端渲染、获取 执行路由转换之前的数据,等等。我们发现自己 试图管理我们从未处理过的复杂性 之前,我们不可避免地会问一个问题:是时候放弃了吗?这 答案是否定的。

这种复杂性很难处理,因为我们混合了两个概念 人类大脑很难推理:突变和 异步性。我称它们为曼妥思和可乐。两者都可以很棒 分开,但它们在一起会造成混乱。 React 之类的库 尝试通过同时删除视图层来解决此问题 异步和直接 DOM 操作。但是,管理状态 您的数据由您决定。这就是 Redux 的用武之地。

跟随 Flux、CQRS 和 Event Sourcing、Redux 的脚步 试图通过强加某些 限制更新的方式和时间。这些限制 体现在 Redux 的三个原则中。

同样来自Redux docs:

核心概念 Redux 本身非常简单。

假设您的应用程序的状态被描述为一个普通对象。例如, 待办事项应用的状态可能如下所示:


  todos: [
    text: 'Eat food',
    completed: true
  , 
    text: 'Exercise',
    completed: false
  ],
  visibilityFilter: 'SHOW_COMPLETED'

这个对象就像一个“模型”,只是没有设置器。这 是为了让代码的不同部分不能改变状态 随意,导致难以重现的错误。

要更改状态中的某些内容,您需要调度一个操作。一个 action 是一个普通的 JavaScript 对象(注意我们没有引入任何 魔术?)描述发生了什么。以下是一些示例操作:

 type: 'ADD_TODO', text: 'Go to swimming pool' 
 type: 'TOGGLE_TODO', index: 1 
 type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' 

强制将每个更改都描述为一个操作,让我们有一个 清楚地了解应用程序中发生的事情。如果有什么 变了,我们知道为什么变了。行动就像是什么的面包屑 已经发生了。最后,为了将状态和动作联系在一起,我们编写了一个 称为减速器的函数。再一次,它没有什么神奇之处——它只是一个 以状态和动作为参数的函数,并返回 应用程序的下一个状态。很难为一个 大应用程序,所以我们编写较小的函数来管理部分状态:

function visibilityFilter(state = 'SHOW_ALL', action) 
  if (action.type === 'SET_VISIBILITY_FILTER') 
    return action.filter;
   else 
    return state;
  


function todos(state = [], action) 
  switch (action.type) 
  case 'ADD_TODO':
    return state.concat([ text: action.text, completed: false ]);
  case 'TOGGLE_TODO':
    return state.map((todo, index) =>
      action.index === index ?
         text: todo.text, completed: !todo.completed  :
        todo
   )
  default:
    return state;
  

我们编写了另一个 reducer 来管理我们的完整状态 应用程序通过调用这两个 reducer 来获取相应的状态键:

function todoApp(state = , action) 
  return 
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  ;

这基本上是 Redux 的全部想法。请注意,我们没有使用 任何 Redux API。它带有一些实用程序来促进这一点 模式,但主要思想是你描述你的状态是怎样的 随时间更新以响应动作对象,以及 90% 的代码 你写的只是纯 JavaScript,没有使用 Redux 本身,它的 API 或任何魔法。

【讨论】:

【参考方案3】:

您可能最好从阅读 Dan Abramov 的这篇文章开始,他在其中讨论了 Flux 的各种实现及其在编写 redux 时的权衡: The Evolution of Flux Frameworks

其次,您链接到的动机页面并没有真正讨论 Redux 的动机,而是讨论了 Flux(和 React)背后的动机。 Three Principles 更特定于 Redux,但仍不处理与标准 Flux 架构的实现差异。

基本上,Flux 有多个存储计算状态更改以响应 UI/API 与组件的交互,并将这些更改作为组件可以订阅的事件进行广播。在 Redux 中,每个组件只订阅一个 store。 IMO 感觉至少 Redux 通过统一(或减少,正如 Redux 所说)流回组件的数据流进一步简化和统一数据流 - 而 Flux 专注于统一数据流的另一端 - 视图型号。

【讨论】:

【参考方案4】:

我是一个早期采用者,并使用 Facebook Flux 库实现了一个中大型单页应用程序。

由于我的谈话有点晚了,我只想指出,尽管我寄予厚望,但 Facebook 似乎认为他们的 Flux 实施是一种概念证明,但它从未得到应有的关注。

我鼓励您使用它,因为它揭示了 Flux 架构的更多内部工作,这很有教育意义,但同时它并没有提供像 Redux 这样的库所提供的许多好处(对于小型项目来说不是那么重要,但对于大型项目来说却非常有价值)。

我们已经决定继续前进,我们将迁移到 Redux,我建议您也这样做;)

【讨论】:

我已经开发 Facebook Flux 应用程序六个月了。而且我仍然不确定迁移时间是否值得 Redux 提供的好处。我将非常感谢您所有关于 Redux 优于 FB Flux 的优缺点! @VolodymyrBakhmatiuk 对我们来说主要是关于减少我们必须编写的样板数量 + 更好的错误处理(例如,如果你触发一个未在常量列表中定义的动作,redux 会大喊大叫 - FB 通量不会,它会导致各种各样的问题)有一些更高级的功能在flux中,但我还没有使用它们 @GuyNesher 应在编译时检测未定义的操作,而不是在运行时检测。 Flow(另一个 Facebook 贡献)允许您这样做。 @DominiquePERETTI - 是的(也可以使用 linting),但它并没有改变这样一个事实,即在运行时没有发现错误有点可悲 我写了一些简单的帮助程序来处理 FBFlux,实际上它似乎比我发现的所有示例 Redux 应用程序更少样板和应用程序设置。在两个开发人员之间持续了 9 个多月的应用程序开发工作,并且从未遇到任何架构问题。【参考方案5】:

这里是 Redux over Flux 的简单解释。 Redux 没有调度程序。它依赖于称为 reducer 的纯函数。它不需要调度程序。每个操作都由一个或多个减速器处理以更新单个存储。由于数据是不可变的,reducers 返回一个新的更新状态来更新 store

欲了解更多信息Flux vs Redux

【讨论】:

关于多个存储,现在在 Redux 中是可行的,在 react-redux 中你可以添加一个键来隔离存储:redux.js.org/faq/storesetup 工作示例:github.com/Lemoncode/redux-multiple-stores【参考方案6】:

我用 Flux 工作了很长时间,现在用 Redux 工作了很长时间。正如 Dan 指出的那样,两种架构并没有太大的不同。问题是 Redux 让事情变得更简单、更干净。它会教你一些关于 Flux 的知识。例如 Flux 是单向数据流的完美示例。分离我们有数据的关注点,它的操作和视图层分离。在 Redux 中,我们拥有相同的东西,但我们也学习了不可变性和纯函数。

【讨论】:

【参考方案7】:

来自 2018 年中期从(几年的)ExtJS 迁移的新 react/redux 采用者:

在沿着 redux 学习曲线向后滑动后,我遇到了同样的问题,并认为纯通量会像 OP 一样简单。

我很快就看到了上面答案中提到的 redux 相对于通量的好处,并将其应用于我的第一个应用程序中。

在再次掌握样板时,我尝试了一些其他状态管理库,我发现最好的是rematch。

比原版 redux 更直观,它减少了 90% 的样板文件并减少了我花在 redux 上的 75% 的时间(我认为图书馆应该这样做) ,我能够立即启动几个企业应用程序。

它也使用相同的 redux 工具运行。这是一个good article,涵盖了一些好处。

因此,对于其他任何在此 SO 帖子中搜索“更简单的 redux”的人,我建议尝试将其作为 redux 的简单替代品,具有所有优点和 1/4 的样板。

【讨论】:

【参考方案8】:

根据这篇文章: https://medium.freecodecamp.org/a-realworld-comparison-of-front-end-frameworks-with-benchmarks-2019-update-4be0d3c78075

您最好使用 MobX 来管理应用中的数据以获得更好的性能,而不是 Redux。

【讨论】:

以上是关于为啥使用 Redux 而不是 Facebook Flux? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 Redux-Observable 而不是 Redux-Saga?

为啥 redux-saga 使用 put 方法而不是 dispatch?

为啥 facebook messenger 和 discord 使用数据库而不是排队系统来获取他们的消息?

为啥 Facebook、Twitter 和 GMail 将其所有数据以 JSON 而不是 HTML 的形式呈现给浏览器?

为啥我们使用 'this->' 而不是 'this'。访问成员?

为啥我们已经有了 mapDispatchToProps 还需要 redux-thunk