为什么通过Facebook Flux使用Redux?[关闭]


1126

我已经阅读了这个答案减少了样板,看了几个GitHub示例,甚至尝试了一点redux(待办事项应用程序)。

据我了解,官方的redux doc动机与传统的MVC架构相比具有优势。但是它没有提供以下问题的答案:

为什么要通过Facebook Flux使用Redux?

这仅仅是编程风格的一个问题:功能性还是非功能性?还是问题出在redux方法之后的abilities / dev-tools中?也许缩放?还是测试?

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

为了回答这个问题,您可以比较实现Redux在通量和Redux上的动机点的复杂性。

以下是来自官方redux doc动机的动机点:

  1. 处理乐观更新(据我了解,这几乎不依赖于第5点。很难在Facebook流量中实现它吗?
  2. 在服务器上渲染(facebook流量也可以做到这一点。与redux相比有什么好处吗?
  3. 在执行路线转换之前获取数据(为什么不能在facebook流量中实现?有什么好处?
  4. 热重载(React Hot Reload可能实现。为什么需要redux?
  5. 撤消/重做功能
  6. 还有其他要点吗?像坚持状态...

73
Redux是“ Facebook Flux”的实现。Flux不是库或框架。它只是Web应用程序的推荐体系结构。我看不到如何将具体实现与激发它的抽象概念进行比较。Facebook对Flux架构的实际实现是Relay,而开源版本仍处于早期阶段。facebook.github.io/relay
查理·马丁

2
@CharlieMartin通过FB Flux提出了类似github.com/facebook/flux/tree/master/examples的应用程序。我当前的项目是在FB Flux(由于FB Flux)上编写的。如果需要,您可以将其视为FB Flux架构之上的Redux架构。
VB_

2
我现在知道了。您想将Facebook的示例Flux实现与Redux的Flux实现进行比较
Charlie Martin

13
中继不是Flux的实现-中继/ GraphQL更关心与服务器一起管理数据获取/查询,而Flux主要关心构造客户端数据模型和视图组件之间的数据流。但是存在一些重叠:在Facebook,我们的应用程序完全使用Flux构建,完全使用Relay构建,或同时使用两者。我们看到一种新兴的模式是让Relay管理应用程序的大部分数据流,但使用侧面的Flux存储来处理应用程序状态的子集
Hal Hal

Answers:


1958

Redux作者在这里!

Redux 与Flux 没有什么不同。总体而言,它具有相同的架构,但是Redux可以通过使用Flux使用回调注册的功能组合来减少一些复杂性。

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

减速机组成

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

另一方面,由于Redux的组成,Redux分页很自然。它一直是reducer的源头,因此您可以编写一个reducer工厂来生成分页减少器,然后在您的reducer树中使用它。之所以如此简单,关键是因为在Flux中存储是平坦的,但是在Redux中,reduce可以通过功能组合来嵌套,就像React组件可以嵌套一样。

此模式还启用了诸如无用户代码undo / redo之类的出色功能。您能想象两行代码将撤消/重做插入Flux应用程序吗?几乎不。再次使用Redux,这归功于reducer的组成模式。我需要强调一点,这没有什么新鲜的-这是Elm Architecture所开创和详细描述的模式,它本身受Flux的影响。

服务器渲染

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

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

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

  • 如果商店是类,那么如何根据请求使用分派器创建和销毁它们?我什么时候注册商店?
  • 如何合并来自商店的数据,然后在客户端重新补充数据?为此,我需要实现特殊方法吗?

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

Redux走得更远:由于只有一个商店(由许多reducers管理),因此您不需要任何特殊的API来管理(重新)水化。您无需“冲洗”或“充水”商店-仅有一个商店,您可以读取其当前状态,或创建具有新状态的新商店。每个请求都获得一个单独的商店实例。了解有关使用Redux进行服务器渲染的更多信息。

同样,在Flux和Redux中都有可能发生这种情况,但是Flux库通过引入大量API和约定来解决此问题,而Redux甚至不必解决它,因为在由于概念上的简单性而获得了第一名。

开发人员经验

实际上,我并没有打算让Redux成为流行的Flux库,而是在我撰写关于ReactEurope的关于时光热装的ReactEurope演讲时写的。我有一个主要目标:可以即时更改减速器代码,甚至可以通过取消操作来“更改过去”,并查看状态是否正在重新计算。

我还没有看到能够执行此操作的单个Flux库。React Hot Loader也不允许您这样做-实际上,如果您编辑Flux商店,它会中断,因为它不知道如何处理它们。

当Redux需要重新加载化简器代码时,它将调用replaceReducer(),并且应用程序将使用新代码运行。在Flux中,数据和功能在Flux存储中纠缠在一起,因此您不能“仅替换功能”。此外,您还必须以某种方式向Dispatcher重新注册新版本,而Redux甚至没有。

生态系统

Redux具有丰富且快速增长的生态系统。这是因为它提供了一些扩展点,例如中间件。它的设计考虑到了用例,例如日志记录,对Promises的支持,Observables路由不变性开发检查持久性等。并非所有这些工具都将有用,但是很高兴能够使用一组可以轻松组合在一起一起工作的工具。

简单

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

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

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

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


另请参阅我对使用Redux与Flux相比的缺点的回答


3
感谢您的回答。。。我是js的新手。在您的回答中,您曾说过flux正在使用单例设计模式。你告诉我他们在哪里使用单例模式...可以举两个例子...我理解单例的

2
我基于Fluxxor(基本上是纯流量)开始了Android / Java实现(Fluxxan)。一旦看到redux,我就被卖了。我有些地方纯粹是为了让人们保持活力,但伙计,你的lib真棒!
frostymarvelous

5
你想学习Redux吗?只需观看此视频即可:youtube.com/watch?
v=ucd5x3Ka3gw

5
我们选择redux是因为它比flux更自以为是。我们一直在为某些代码应该如何/去哪里而斗争,等等。Redux为我们消除了所有这些混乱。我们使用redux构建了适用于Web和react-native的应用程序,真是太神奇了!
SomethingOn

1
github.com/reactjs/redux/blob/…行是我正在寻找一个星期的问题的答案:如何构造存储和reducer,以便可以处理在不同上下文中使用的可重用组件的多个实例而无需重复逻辑。答案似乎是:使用三个级别的深度存储:第一个级别:组件的名称(“分页”),第二个级别:容器的名称(“ stargazersByRepo”),第三个级别:容器的唯一键/ ID(${login}/${name})。非常感谢你!
qbolec

101

在Quora中,有人说

首先,完全可以使用不带Flux的React编写应用程序。

我创建的这个可视化图表也显示了两者的快速视图,对于不想阅读完整说明的人们来说,可能是一个快速答案: 通量vs Redux

但是,如果您仍然想了解更多信息,请继续阅读。

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

也许您会觉得Redux恰好适合您的应用程序,也许您会发现Redux正在尝试解决您并未真正遇到的问题。

如果直接从Redux开始,则可能会得到过度设计的代码,与没有Redux相比,代码更难维护且存在更多错误。

来自Redux docs

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

管理这种不断变化的状态非常困难。如果一个模型可以更新另一个模型,那么一个视图可以更新一个模型,该模型可以更新另一个模型,这又可能导致另一个视图更新。在某些时候,您不再了解应用程序中发生的情况,因为您无法控制其状态的时间,原因和方式。当系统是不透明且不确定的系统时,很难重现错误或添加新功能。

好像还不够糟糕,请考虑一下新要求在前端产品开发中变得很普遍。作为开发人员,我们有望处理乐观更新,服务器端渲染,在执行路由转换之前获取数据等。我们发现自己试图管理一种前所未有的复杂性,并且不可避免地会问一个问题:是时候该放弃了吗?答案是不。

这种复杂性很难处理,因为我们混用了两个人类大脑难以理解的概念:突变和异步性。我称他们为Mentos和可乐。两者分开时可能很棒,但在一起会造成混乱。像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'
}

该对象就像一个“模型”,只是没有设置器。这样一来,代码的不同部分就无法任意更改状态,从而导致难以重现的错误。

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

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

强制将每个更改描述为一项操作,使我们对应用程序中发生的事情有了清晰的了解。如果有什么变化,我们知道为什么会变化。动作就像发生了什么的面包屑。最后,为了将状态和动作联系在一起,我们编写了一个称为reducer的函数。同样,这没什么神奇的-它只是一个将状态和操作作为参数并返回应用程序的下一个状态的函数。对于大型应用程序很难编写这样的功能,因此我们编写了一些较小的功能来管理部分状态:

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;
  }
}

然后,我们编写另一个精简器,通过调用这两个精简器以获取相应的状态键来管理应用程序的完整状态:

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

这基本上是Redux的整体思想。请注意,我们尚未使用任何Redux API。它带有一些实用程序来简化这种模式,但是主要思想是您描述如何随着时间的推移响应操作对象来更新状态,并且您编写的代码90%只是纯JavaScript,而没有使用Redux本身,其API或任何魔术。


57

最好从阅读Dan Abramov的这篇文章开始,他在写Redux时讨论Flux的各种实现及其权衡: Flux Frameworks的演变。

其次,您链接到的动机页面并没有真正讨论Redux的动机,而是讨论Flux(和React)背后的动机。尽管仍然没有解决与标准Flux架构的实现差异,但“ 三项原则”是Redux所特有的。

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


27

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

我在谈话中有些晚了,我只想指出,尽管我最大的希望是,Facebook似乎将Flux的实现视为概念的证明,并且从未受到应有的重视。

我鼓励您使用它,因为它展示了Flux架构的更多内部工作,这是很有教育意义的,但同时却没有像Redux这样的库提供很多好处(这些没有对于小型项目而言很重要,但对于大型项目则变得非常有价值)。

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


我已经开发了六个月的Facebook Flux应用程序。而且我仍然不确定迁移时间是否值得Redux提供的好处。非常感谢您对Redux在FB上的优缺点的所有评论!
VB_

1
@VolodymyrBakhmatiuk对我们来说,主要是减少我们必须编写的样板数量+更好的错误处理(例如,如果您触发未在常量列表中定义的操作,则redux会大喊大叫-FB流量不会,并且可能导致所有各种各样的问题)在磁通中还有一些更高级的功能,但是我还没有使用过
Guy Nesher

1
@GuyNesher应该在编译时而不是运行时检测到未定义的动作。Flow(Facebook的另一项贡献)使您可以这样做。
多米尼克·佩雷蒂

@DominiquePERETTI-是的(可以使用linting),但是它并不能改变这样一个事实,那就是在运行时未捕获错误有点可悲
Guy Nesher

我写了一些简单的帮助程序来处理FBFlux,实际上似乎比我发现的所有示例Redux应用程序都要少一些样板和应用程序设置。在两个开发人员之间的一个应用程序上工作了9个月以上,并且从没有任何架构问题。
rob2d

20

这是Redux over Flux的简单说明。Redux没有调度程序,它依赖于称为reducers的纯函数。它不需要调度程序。每个动作由一个或多个reduce处理,以更新单个存储。由于数据是不可变的,reduces返回一个新的更新状态,该状态更新了商店在此处输入图片说明

有关更多信息,Flux vs Redux


关于多个商店,现在在Redux中是可行的,在react-redux中,您可以添加一个密钥来隔离商店:redux.js.org/faq/storesetup工作示例:github.com/Lemoncode/redux-multiple-stores
Braulio

6

我在Flux工作了很长时间,现在在Redux中工作了很长时间。正如Dan所指出的,两种架构都没有太大不同。事实是Redux使事情变得更简单,更清洁。它教会了您有关Flux的一些知识。例如,Flux是单向数据流的完美示例。将关注点分离到我们拥有数据,其操作和视图层分离的位置。在Redux中,我们有相同的东西,但我们也了解不变性和纯函数。


5

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

向后滑下redux学习曲线后,我遇到了相同的问题,并认为纯通量将像OP一样简单。

我很快看到了redux相对于通量的好处,如上面的答案所述,并且正在将其用于我的第一个应用程序。

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

vanilla redux直观得多,它减少了90%的样板,减少了75%的我在redux上花费的时间(我认为是图书馆应该做的事情),我能够得到一些企业应用程序马上去。

它还使用相同的redux工具运行。这是一篇很好的文章,涵盖了一些好处。

因此,对于到达此SO职位搜索“更简单的redux”的任何人,我建议您尝试一下它作为redux的一种简单替代方法,它具有所有优势和1/4的样板。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.