为了账号安全,请及时绑定邮箱和手机立即绑定

为什么通过Facebook Flux使用Redux?

/ 猿问

为什么通过Facebook Flux使用Redux?

慕标5265247 2019-12-06 15:52:58

我已经阅读了这个答案,减少了样板,看了几个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. 还有其他要点吗?像坚持状态...


查看完整描述

3 回答

?
翻过高山走不出你

Redux作者在这里!


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


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


减速机组成

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


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


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


服务器渲染

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


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


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


如果商店是类,那么如何根据请求使用分派器创建和销毁它们?我什么时候注册商店?

如何合并来自商店的数据,然后在客户端重新补充数据?为此,我需要实现特殊方法吗?

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


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


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


开发人员经验

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

//img4.sycdn.imooc.com/5dea09000001cea607760688.jpg

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


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


生态系统

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


简单

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


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


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


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


查看完整回答
反对 回复 2019-12-06
?
三国纷争

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

  }

}

然后,我们编写另一个reducer,通过调用这两个reducer来对应的状态键来管理应用程序的完整状态:


function todoApp(state = {}, action) {

  return {

    todos: todos(state.todos, action),

    visibilityFilter: visibilityFilter(state.visibilityFilter, action)

  };

}

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


查看完整回答
反对 回复 2019-12-06
?
慕丝7291255

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

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

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


查看完整回答
反对 回复 2019-12-06

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信