题 为什么在Facebook Flux上使用Redux?


我读了 这个答案减少样板,看了几个GitHub的例子,甚至尝试了redux(todo apps)。

我认为, 官方redux doc动机 提供与传统MVC架构相比的优点。但它没有提供问题的答案:

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

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

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

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

以下是动机点 官方redux doc动机

  1. 处理乐观的更新(据我了解,这几乎不取决于第五点。在facebook flux中实现它难吗?
  2. 在服务器上渲染(facebook flux也可以做到这一点。与redux相比有什么好处?
  3. 在执行路由转换之前获取数据(为什么在facebook中无法实现?有什么好处?
  4. 热重装(有可能 React Hot Reload。为什么我们需要redux?
  5. 撤消/重做功能
  6. 还有其他一点吗?像坚持国家一样......

1006
2017-09-08 15:05


起源


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


答案:


Redux作者在这里!

Redux不是  不同于Flux。总体而言,它具有相同的架构,但Redux能够通过使用Flux使用回调注册的功能组合来削减一些复杂角落。

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

减速剂成分

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

另一方面,由于减速器的成分,Redux的分页很自然。它一直是减速器,所以你可以写一个 减速机工厂,产生分页减速器 接着 在你的reducer树中使用它。这么简单的关键因素是因为 在Flux中,商店是平的,但在Redux中,reducers可以通过功能组合嵌套,就像React组件可以嵌套一样。

此模式还支持非用户代码等精彩功能 撤销重做您能想象将Undo / Redo插入到两行代码的Flux应用程序中吗?几乎不。有了Redux,它就是 - 感谢减速机组成模式。我需要强调的是,没有什么新的东西 - 这是开创性和详细描述的模式 榆树建筑 它本身受到Flux的影响。

服务器渲染

人们使用Flux在服务器上渲染得很好,但是看到我们有20个Flux库,每个都试图让服务器呈现“更容易”,也许Flux在服务器上有一些粗糙的边缘。事实是Facebook没有做太多的服务器渲染,因此他们并没有非常关注它,而是依靠生态系统来简化它。

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

您仍需要在Flux中解决以下问题(您自己或在您喜欢的Flux库的帮助下,例如 惊讶 要么 Alt键):

  • 如果商店是类,我如何使用每个请求的调度程序创建和销毁它们?我什么时候注册商店?
  • 如何保存商店中的数据,然后在客户端上重新水化?我需要为此实现特殊方法吗?

诚然,Flux框架(不是vanilla Flux)可以解决这些问题,但我发现它们过于复杂。例如, Flummox要求您实施 serialize() 和 deserialize() 在你的商店。 Alt通过提供来解决这个问题 takeSnapshot() 它会自动在JSON树中序列化您的状态。

Redux走得更远: 由于只有一个商店(由许多减速机管理),您不需要任何特殊的API来管理(重新)水合作用。 您不需要“刷新”或“保湿”商店 - 只有一个商店,您可以读取其当前状态,或创建具有新状态的新商店。每个请求都有一个单独的商店实例。 阅读有关Redux服务器渲染的更多信息。

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

开发经验

我实际上并不打算让Redux成为一个受欢迎的Flux库 - 我在写作时正在编写它 ReactEurope谈论热时间旅行的重新加载。我有一个主要目标: 可以动态更改减速器代码,甚至可以通过交叉操作“更改过去”,并查看重新计算的状态。

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

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

生态系统

Redux有一个 丰富而快速发展的生态系统。这是因为它提供了一些扩展点,如 中间件。它的设计用例如 记录, 支持 承诺观测路由不变性开发检查坚持等等,记住。并非所有这些都会变得有用,但很高兴能够访问一组可以轻松组合在一起工作的工具。

简单

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

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

与大多数Flux库不同,Redux API表面很小。如果您删除了开发人员警告,评论和完整性检查,那就是 99行。调试没有棘手的异步代码。

您实际上可以阅读它并了解Redux的所有内容。


也可以看看 我对使用Redux与Flux相比的缺点的答案


1807
2017-10-03 08:26



谢谢你的回答...我是js的新手......在你的回答中,你说通量是使用单件设计模式...你能告诉我他们正在使用什么样的设计模式......并且在通量可以你告诉我他们在哪里使用单件模式...你能给出一个例子......我从这里了解设计模式是什么 独生子
我开始基于Fluxxor的Android / Java实现(Fluxxan)(基本上是纯粹的通量)。有一次我看到redux,我被卖了。有些部分我保持纯粹的流量,但是男人,你的lib很棒! - frostymarvelous
你想学习Redux吗?只看这个视频: youtube.com/watch?v=ucd5x3Ka3gw - gsalgadotoledo
我们之所以选择redux,是因为它比通量更具有见解。我们一直在争论某些代码应该如何/在哪里等等.Redux为我们消除了所有这些混乱。我们已经构建了带有redux for web和react-native的应用程序,这太棒了! - SomethingOn
担 is always on point 阿布拉莫夫!谢谢你的解释 - cabolanoz


有人说,在Quora 

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

还有这个 视觉图 我创建的内容显示了两者的快速视图,可能是对不想阅读整个解释的人们的快速回答: Flux vs Redux

但如果您仍然对更多信息感兴趣,请继续阅读。

我相信你应该从纯粹的React开始,然后学习Redux和Flux。   在你对React有一些实际经验之后,你会看到   Redux是否对你有帮助。

也许你会觉得Redux完全适合你的应用,也许你   会发现,Redux正试图解决你不是的问题   真的经历过。

如果直接使用Redux,最终可能会过度设计   代码,代码更难维护,甚至更多的错误   终极版。

Redux文档

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

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

好像这还不够糟糕,考虑新的要求   在前端产品开发中很常见。作为开发人员,我们是   期望处理乐观更新,服务器端呈现,提取   执行路由转换之前的数据,等等。我们发现自己   试图管理我们从未必须处理的复杂性   之前,我们不可避免地提出这样一个问题:是时候放弃了吗?该   答案是否定的

由于我们混合了两个概念,因此难以处理这种复杂性   这是人类思维难以推理的原因:突变和   异步性。我称他们为Mentos和Coke。两者都很棒   分开,但他们在一起造成一团糟。像React这样的图书馆   尝试通过删除两者来解决视图层中的此问题   异步和直接DOM操作。但是,管理状态   您的数据由您自己决定。这是Redux的用武之地。

追随Flux,CQRS和Event Sourcing,Redux的脚步   试图通过强加某些来预测状态突变   对更新如何以及何时发生的限制。这些限制   反映了Redux的三个原则。

也来自 Redux文档

核心概念
 Redux本身很简单。

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

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

这个对象就像一个“模型”,除了没有setter。这个   是这样,代码的不同部分不能改变状态   任意地,导致难以重现的错误。

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

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

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

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,或任何魔术。


74
2018-03-22 12:59



复制意大利面也不错。 :) - Léon Pelletier


你可能最好开始阅读Dan Abramov的这篇文章,他在撰写redux时讨论了Flux的各种实现及其权衡: 流量框架的演变

其次,你链接的动机页面并没有真正讨论Redux的动机,而是Flux(和React)背后的动机。该 三原则 虽然仍然没有处理与标准Flux架构的实现差异,但更具特定的Redux。

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


50
2017-09-23 14:51





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

由于我的谈话有点迟,我只想指出,尽管我最好的希望Facebook似乎认为他们的Flux实施是一个概念证明,它从未得到应有的关注。

我鼓励你玩它,因为它暴露了Flux架构的更多内部工作,这是非常有教育意义,但同时它没有提供像Redux这样的库提供的许​​多好处(它们不是这对小型项目很重要,但对大型项目非常有价值)。

我们决定继续前进,我们将转向Redux,我建议你这样做;)


22
2018-01-05 13:45



我已经开发了六个月的Facebook Flux应用程序。我仍然不确定迁移时间是否值得Redux提供的好处。我非常感谢所有关于Redux优于FB flux的优缺点的评论! - Volodymyr Bakhmatiuk
@VolodymyrBakhmatiuk对我们来说,主要是减少我们必须编写的样板量+更好的错误处理(例如,如果你触发一个未在你的常量列表中定义的动作,则会减少你的声音 - FB通量不会,它会导致所有各种各样的问题)有一些更先进的功能,但我还没有使用它们 - Guy Nesher
@GuyNesher应该在编译时检测未定义的操作,而不是在运行时检测。 Flow(另一个Facebook贡献)允许您这样做。 - Dominique PERETTI
@DominiquePERETTI - true(也可以使用linting)但它并没有改变在运行时没有捕获错误的事实有点难过 - Guy Nesher
我写了几个简单的助手来处理FBFlux,它实际上似乎是 减 应用程序和应用程序设置比我找到的所有Redux应用程序示例。在两个开发人员之间工作了9个月以上的应用程序,并且从未对架构有任何问题。 - rob2d


以下是Redux over Flux的简单解释。 Redux没有调度程序。它依赖于名为reducers的纯函数。它不需要调度员。每个操作由一个或多个Reducer处理以更新单个存储。由于数据是不可变的,因此reducers返回更新存储的新更新状态enter image description here

了解更多信息 http://www.prathapkudupublog.com/2017/04/flux-vs-redux.html


13
2018-04-18 14:27





我在Flux工作了很长时间,现在使用Redux已经很长时间了。正如丹指出的那样,两种架构都没有那么不同。事情是,Redux使事情更简单,更清洁。它会在Flux上教你一些东西。例如,Flux是单向数据流的完美示例。我们将数据,操作和视图层分开的问题分离。在Redux中我们有相同的东西,但我们也学习了不变性和纯函数。


2
2018-01-25 12:26





助焊剂 是一种模式和 终极版 是一个图书馆。

Flux是观察者模式的一个奇特的名称,修改了一点点以适应React,但Facebook发布了一些工具来帮助实现Flux模式,因此以下是使用这些工具之间的区别(通常称为使用Flux )并使用Redux。

Flux和Redux都有动作。可以将操作与事件(或触发事件)进行比较。在Flux中,一个动作是一个简单的JavaScript对象,这也是Redux中的默认情况,但是当使用Redux中间件时,动作也可以是函数和承诺。

使用Flux,每个应用程序有多个存储区是一种惯例;每个商店都是一个单身对象。在Redux中,惯例是每个应用程序有一个存储区,通常在内部分成数据域(如果需要更复杂的场景,可以创建多个Redux存储区)。

Flux有一个调度程序,所有操作都必须通过该调度程序。这是一个单身对象。 Flux应用程序不能有多个调度程序。这是必需的,因为Flux应用程序可以有多个存储,并且这些存储之间的依赖关系需要一个管理器,即调度程序。

Redux没有调度程序实体。相反,商店已经完成了调度过程.Redux商店公开了一些简单的API函数,其中之一就是调度操作。

在Flux中,基于接收到的操作对数据执行的操作的逻辑将写入存储本身。商店还具有公开展示的数据部分的灵活性。 Flux应用程序中最聪明的玩家就是商店。

在Redux中,基于接收到的操作对数据执行的操作的逻辑在reducer函数中,该函数将被调度的每个操作(通过存储API)调用。如果没有reducer功能,则无法定义商店。 Redux reducer是一个简单的函数,它接收先前的状态和一个动作,并根据该动作返回新的状态。在Redux应用程序中,您可以将reducer拆分为更简单的功能,就像使用任何其他功能一样。 Redux中最聪明的玩家是减速器。

在Redux中,作为商店的状态,公开的内容也没有很大的灵活性。 Redux将公开从商店的减速器返回的任何东西。这是一个约束。

另一个更大的限制是商店的状态不可变(或者真的,不应该)。在Flux中没有这样的约束,你可以根据需要改变状态。 Redux中的状态不变性通过使Reducer纯函数(没有副作用)很容易实现。 Redux reducers总是复制它们收到的状态并返回状态副本的修改版本,而不是原始对象本身。虽然这是一个很大的限制因素,但它可以让生活更加轻松。


0
2018-06-24 07:13