为什么在Facebook上使用Redux?

我读过这个答案 , 减less了样板 ,看了几个GitHub的例子,甚至尝试了一点点(todo应用程序)。

据我所知, 官方的redux doc动机提供了优于传统的MVC架构。 但是它没有提供对这个问题的答案:

为什么你应该使用Facebook上的stream量的Redux?

这只是一个编程风格的问题:function与非function? 或者问题是在redux方法中的能力/开发工具? 也许缩放? 还是testing?

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

为了回答这个问题,你可以比较实现redux在flux和redux上的动机点的复杂性。

以下是官方的文件格式动机 :

  1. 处理乐观的更新( 据我所知,它很难取决于第五点,难以在fbstream量中实现它
  2. 在服务器上进行渲染( fb flux也可以做到这一点,与redux相比有什么好处?
  3. 在执行路由转换之前获取数据( 为什么在fb flux中无法实现?有什么好处?
  4. 热重新加载( React Hot Reload有可能,为什么我们需要重新加载 ?
  5. 撤销/重做function
  6. 还有其他的要点吗 像持续的状态…

Redux的作者在这里!

Redux和Flux没有什么不同。 总的来说,它具有相同的体系结构,但是Redux能够使用Flux使用callback注册的function组合来削减一些复杂性。

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

还原剂组成

以分页为例。 我的Flux + React路由器的例子处理分页,但代码是可怕的。 其糟糕的原因之一是, Flux使得在商店中重复使用function是不自然的。 如果两个商店需要响应不同的动作来处理分页,他们或者需要从一个普通的基础商店inheritance(当你使用inheritance时,你将自己locking在一个特定的devise中),或者从处理函数调用一个函数将需要以某种方式在Flux商店的私人州进行操作。 整个事情是混乱的(虽然绝对在可能的领域)。

另一方面,使用Redux分页是自然的减速器组成。 它是减速器,所以你可以写一个减速器工厂生成分页减速器 ,然后在你的减速器树中使用它 。 关键之所以如此简单,是因为在Flux中,商店是平坦的,但在Redux中,reducer可以通过function组合嵌套,就像React组件可以嵌套一样。

这种模式还可以实现诸如非用户代码撤销/重做等奇妙function。 你能想象把Undo / Redo插入到两行代码的Flux应用程序中吗? 几乎不。 随着Redux,它是 – 重要的 ,由于减速机组成模式。 我需要强调一下,没有什么新的东西 – 这是Elm Architecture开创和描述的模式,它本身受Flux的影响。

服务器渲染

人们已经使用Flux在服务器上渲染,但是看到我们有20个Flux库,每个试图使服务器渲染“更容易”,Flux可能在服务器上有一些粗糙的边缘。 事实是,Facebook没有做太多的服务器渲染,所以他们一直没有非常关心它,并依靠这个生态系统来使它更容易。

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

Flux还需要解决以下问题(无论是您自己还是您最喜欢的Flux库(如Flummox或Alt )的帮助):

  • 如果商店是类,那么如何根据请求创build和销毁调度程序? 我什么时候注册商店?
  • 我如何从商店补充水分,然后在客户端补充水分? 我需要为此实现特殊的方法吗?

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

Redux更进一步: 由于只有一个商店(由许多reducerpipe理),你不需要任何特殊的API来pipe理(重新)水合。 您不需要“冲洗”或“保存”商店 – 只有一个商店,您可以阅读其当前状态,或创build一个新的状态的新商店。 每个请求获取一个单独的商店实例。 阅读更多关于使用Redux进行服务器渲染

再次,这是Flux和Redux中可能的情况,但Flux库通过引入大量的API和约定来解决这个问题,Redux甚至不需要解决这个问题,因为它没有这个问题首先感谢概念简单。

开发者体验

我实际上并不打算让Redux成为一个受欢迎的Flux库 – 我是在我的ReactEurope关于时间旅行热重载的谈话中写的。 我有一个主要目标: 可以dynamic更改Reducer代码,甚至可以通过删除操作来“改变过去”,并查看重新计算的状态。

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

当Redux需要重新加载Reducer代码时,它会调用replaceReducer() ,并使用新代码运行该应用程序。 在Flux中,数据和function被Flux商店纠缠,所以你不能“只是replacefunction”。 此外,你必须以某种方式重新注册与Dispatcher的新版本 – 什么Redux甚至没有。

生态系统

Redux拥有丰富且快速增长的生态系统 。 这是因为它提供了一些扩展点,比如中间件 。 它的devise与logging ,支持Promise , Observable , 路由 , 不变性开发检查 , 持久性等用例有关。 并不是所有这些都会变得有用,但能够访问一系列可以轻松组合在一起工作的工具是很好的。

简单

Redux保留了Flux的所有优点(logging和重播动作,单向数据stream,相关突变),并增加了新的优点(简单的撤消重做,热重载),而不引入Dispatcher和商店注册。

保持简单是很重要的,因为它让你保持理智,同时实现更高层次的抽象。

与大多数Flux库不同,Redux API表面很小。 如果您删除了开发人员警告,注释和完整性检查,则为99行 。 没有棘手的asynchronous代码来debugging。

你可以真正阅读并理解所有的Redux。


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

您可能最好从Dan Abramov的这篇文章开始阅读,在那里他讨论Flux的各种实现及其在编写redux时的权衡: Flux框架的演变

其次,你链接到的动机页面并没有像Flux(和React)背后的动机一样讨论Redux的动机。 “ 三原则”更多的是Redux的具体细节,但仍然没有涉及到与标准Flux架构的实现差异。

Flux基本上有多个“存储”,它们计算状态变化以响应与组件的UI / API交互,并将这些更改作为组件可以订阅的事件广播。 在Redux中,每个组件订阅的商店只有一个。 海事组织至less像Redux一样,通过统一数据stream(或者减lessRedux的说法)来进一步简化和统一数据stream,将数据stream返回到组件 – 而Flux专注于统一数据stream的另一端 – 视图到模型。

在Quora,有人说 :

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

我创build的这个视觉图也展示了这两个视图,对于不想阅读整个解释的人来说可能是一个快速的答案: 在这里输入图像描述

但如果你还有兴趣知道更多,请继续阅读。

我相信你应该从纯粹的React开始,而不是学习Redux和Flux。 在使用React之后,您将看到Redux是否对您有所帮助。

也许你会觉得Redux正好适合你的应用程序,也许你会发现,Redux正在试图解决你没有真正遇到的问题。

如果您直接使用Redux,那么最终可能会出现过度devise的代码,难以维护的代码以及更多的错误,而不是Redux。

从Redux文档 :

动机
随着对JavaScript单页面应用程序的要求变得越来越复杂,我们的代码必须比以前更多地处理状态。 此状态可以包括服务器响应和caching数据,以及尚未保存到服务器的本地创build的数据。 UI状态的复杂性也在增加,因为我们需要pipe理活动路线,选定的标签,旋钮,分页控件等等。

pipe理这个不断变化的状态是很难的。 如果一个模型可以更新另一个模型,那么一个视图可以更新一个模型,这个模型会更新另一个模型,而这又可能导致另一个视图更新。 在某些时候,你不再理解你的应用程序会发生什么情况,因为你已经失去了对其状态的何时,为什么和怎样的控制。 当系统不透明且不确定时,很难重现错误或添加新function。

就好像这还不够糟糕,考虑到新的要求在前端产品开发中变得很普遍。 作为开发人员,我们需要处理乐观的更新,服务器端渲染,在执行路由转换之前获取数据等等。 我们发现自己试图去处理一个我们以前从来没有处理过的复杂问题,而且我们不可避免地提出这个问题:是放弃的时候了吗? 答案是不。

这个复杂性很难处理,因为我们混合了两个对于人类思维来说很难理解的概念:突变和asynchronous性。 我叫他们曼妥思和可乐。 两人可以很好地分离,但他们一起创造一个烂摊子。 像React这样的库试图通过去除asynchronous和直接的DOM操作来解决视图层中的这个问题。 但是,pipe理数据的状态由您决定。 这是Redux进入的地方。

通过Flux,CQRS和Event Sourcing的步骤,Redux试图通过对更新可能发生的方式和时间施加一定的限制来使状态变化可预测。 这些限制反映在Redux的三个原则中。

另外从Redux文档 :

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

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

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

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

要改变这个状态,你需要发送一个动作。 一个动作是一个普通的JavaScript对象(注意我们怎么不引入任何魔法?)来描述发生的事情。 以下是一些示例操作:

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

强化每一个变化都被描述为一个行动,让我们清楚地了解应用程序正在发生的事情。 如果有什么改变,我们知道为什么改变。 行动就像发生了什么事情的面包屑。 最后,为了将状态和动作绑定在一起,我们编写了一个称为reducer的函数。 再一次,没有什么魔力 – 它只是一个以状态和动作为参数的函数,并返回应用程序的下一个状态。 为大型应用程序编写这样一个函数是很难的,所以我们编写pipe理部分状态的小函数:

 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来获取相应的状态键来pipe理我们的应用程序的完整状态:

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

这基本上是Redux的整个想法。 请注意,我们还没有使用任何Redux API。 它提供了一些实用工具来简化这种模式,但主要想法是描述了如何随着时间的推移更新状态以响应操作对象,并且您编写的代码的90%只是普通的JavaScript,没有使用Redux本身,API,或任何魔法。

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

由于谈话有点迟,我只想指出,尽pipe我对Facebook的最大希望似乎认为他们的Flux实现是一个概念的certificate,并没有得到应有的重视。

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

我们已经决定前进,我们将会转向Redux,我build议你也这样做;)

这是Redux over Flux的简单解释。 Redux没有调度程序,它依赖于称为reducer的纯函数。 它不需要调度员。 每个操作都由一个或多个减速器处理以更新单个存储。 由于数据是不可变的,因此reducer会返回一个新的更新状态来更新商店 在这里输入图像描述

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