javascript - immutable中文 - 为什么通过Facebook Flux使用Redux?



reactjs reactjs-flux (6)

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

https://ffff65535.com


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 deserialize() 。 Alt通过提供 takeSnapshot() 来自动解决此问题,该 takeSnapshot() 会自动在JSON树中序列化您的状态。

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

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

开发人员经验

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

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

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

生态系统

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

简单

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

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

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

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

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


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


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

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

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


来自一个新的react / redux采用者,它是在2018年中期从ExtJS(几年)迁移而来的:

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

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

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

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

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

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


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

有关更多信息, Flux vs Redux


在Quora中,有人说

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

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

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

我相信您应该从纯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或任何魔术。





redux