使用Redux而不是Flux的缺点可能是什么?

248

我最近刚刚发现了Redux。它看起来很不错。使用Redux相比Flux有什么缺点、需要注意的地方或妥协吗?谢谢。

7个回答

416

我是Redux的作者!

我要说的是,你在使用Redux时需要做出以下妥协:

  • 你需要学会避免更改数据。 Flux对更改数据没有意见,但Redux不喜欢更改数据,许多与Redux配套的包也假定您从不更改状态。您可以使用仅限于开发环境的包(例如redux-immutable-state-invariant),使用Immutable.js,或信任自己和团队编写非变异代码,但这是您需要了解的事情,并且这需要成为您团队接受的有意识的决策。

  • 你将不得不仔细选择你的包。尽管Flux明确不会试图解决“附近”的问题,例如撤消/重做持久性表格,但Redux具有中间件和存储增强器等扩展点,并且它已经产生了一个年轻但丰富的生态系统。这意味着大多数软件包都是新想法,尚未获得足够使用量的关键性。您可能会依赖某些东西,几个月后明显是个坏主意,但现在很难判断。

  • 你暂时还没有完美的Flow集成。 Flux目前允许您进行非常印象深刻的静态类型检查,Redux目前还不支持。我们会到那里的,但需要一些时间。

我认为对于初学者来说,第一个是最大的障碍,对于过于热衷于早期采用的人来说,第二个可能会成为问题,第三个则是我个人的小怨恨。除此之外,我认为使用Redux没有任何特定的缺点,Flux也避免不了它,有些人甚至认为它相比Flux还有一些优势。


另请参阅我在使用Redux的优势上的回答。


1
很棒的答案。Redux及其补充包为什么要避免使用突变,有简单的解释吗? - Michael Ramos
8
简而言之,突变使得难以检查哪些状态的部分已更改,以便有效地重新绘制仅更改的UI部分。它们还使得调试更加困难,并且像https://github.com/omnidan/redux-undo这样的库不可能实现。最后,在https://github.com/gaearon/redux-devtools中进行时间旅行将无法工作,如果状态被突变了。 - Dan Abramov
@DanAbramov,不可变性如何帮助在Redux中实现高效的重绘? 例如,在react-redux中使用shallowEqual检查来确定状态是否更改。但它可以被替换为deepEqual或JSON.stringify和比较。 最终它有点低性能 - 但它是纯计算而不涉及DOM - 所以足够快。 无论如何,渲染本身都是相同的。 - amakhrov
@amakhrov,deepEqual或JSON.stringify非常慢。对于真正的应用程序来说,它们不够快,特别是如果您要比较每个视图的数据。 - Dan Abramov
好的,我明白了。听起来不可变性使脏检查更有效率,而不是使重绘更有效率。 - amakhrov
@DanAbramov 在这个充满偏见的行业中,看到有人(尤其是作者)提供软件包/库的优缺点,真是令人耳目一新。这才是关于软件讨论应该进行的方式,也是做出明智决策的方法,而不是“最新的库”方法。请继续保持! - Ian

37

无论是Redux还是Flux,在涵盖许多常见模式(特别是涉及异步数据获取的模式)时,都需要大量的样板代码。Redux文档已经有了几个示例来减少样板代码:http://redux.js.org/docs/recipes/ReducingBoilerplate.html。你可以从像Alt或Fluxxor这样的Flux库中获得你可能需要的一切,但Redux更喜欢自由而不是功能。这可能对某些开发人员来说是一个缺点,因为Redux对你的状态做出了某些假设,可能会被无意忽略。

你真正回答你的问题的唯一方法是尝试Redux,如果可能的话,可以在个人项目中尝试。Redux的出现是因为需要更好的开发者体验,并且它偏向于函数式编程。如果你不熟悉诸如reducer和函数组合之类的功能概念,那么你可能会变慢,但只会稍微慢一些。在数据流中采用这些思想的优点是更容易进行测试和可预测性。

免责声明:我从Flummox(一种流行的Flux实现)迁移到了Redux,好处远远超过了任何缺点。我更喜欢我的代码中有更少的魔法。较少的魔法需要付出一点更多的样板代码的代价,但这是一个非常小的代价。


17

FluxRedux . . .

Redux 不是一个纯粹的 Flux 实现,但绝对受到了 Flux 的启发。最大的区别在于它使用一个单一的存储器,该存储器包装一个状态对象,其中包含您应用程序的所有状态。与您在 Flux 中创建存储器不同,在 Redux 中,您将编写减速器函数,这些函数将更改单个对象状态。此对象表示您应用程序中的所有状态。在 Redux 中,您将获得当前操作和状态,并返回新状态。这意味着操作是顺序的,状态是不可变的。这使我认为 Redux 最明显的缺点。


Redux 支持不可变的immutable概念。

为什么要使用不可变性?

这里有几个原因:
1. 一致性 - 存储的状态总是被reducer更改,因此很容易跟踪谁更改了什么。
2. 性能 - 因为它是不可变的,Redux只需要检查前一个状态!==当前状态,如果是,则进行渲染。无需每次循环状态来确定渲染。
3. 调试 - 新的惊人概念,如时间旅行调试热重载

更新:如果这还不够说服你,请观看Lee Byron关于不可变用户界面的精彩演讲。

Redux需要开发者在代码库/库中保持这个理念的纪律性。您需要确保选择库并以不可变的方式编写代码。 如果您想了解Flux概念的不同实现(以及哪种最适合您的需求),请查看this 有用的比较。 话虽如此,我必须承认,就JS未来的发展而言,Redux是一个方向(当我写下这些话时)。

15
使用Redux相比其他Flux替代方案的最大优势之一是它有能力重新引导你的思维走向更加功能化的方法。一旦你理解了所有连接的电线,你就会意识到它在设计上的惊人优雅和简单,而且再也无法回头。

4

我更喜欢使用Redux,因为它仅使用一个存储,相比于Flux,使状态管理更加容易。此外,Redux DevTools是一个非常有用的工具,可以让您查看一些有用的数据以及与React开发工具一起使用。

另外,Redux在与其他流行框架(如Angular)一起使用时更加灵活。无论如何,让我们看看Redux如何介绍自己。

三个原则

你整个应用程序的状态都存储在单个存储中的对象树中。

这使得创建通用应用程序变得容易,因为您的服务器的状态可以被序列化并转换为客户端,而不需要额外的编码工作。单个状态树还使得调试或检查应用程序变得更加容易;它也使您能够在开发中持久化应用程序状态,以获得更快的开发周期。如果所有状态都存储在单个树中,则某些功能传统上很难实现,例如撤销/重做,可能会突然变得容易。

console.log(store.getState())

/* Prints
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
*/

状态是只读的

改变状态的唯一方法是发出一个操作,即描述发生了什么的对象。

这确保视图和网络回调都不会直接写入状态。相反,它们表达了转换状态的意图。由于所有更改都是集中的,并且按照严格的顺序逐个发生,因此没有微妙的竞争条件需要注意。由于操作只是普通对象,因此可以记录、序列化、存储并在以后用于调试或测试目的重播。

store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
})

store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
})

使用纯函数进行更改

为了指定如何通过操作转换状态树,您需要编写纯函数。

Reducer仅仅是纯函数,它接受先前的状态和一个动作并返回下一个状态。请记住始终返回新的状态对象,而不是改变先前的状态。您可以从一个单一的Reducer开始,随着应用程序的增长,将其拆分成管理状态树特定部分的较小的Reducer。因为Reducer只是函数,所以您可以控制它们被调用的顺序、传递额外的数据,甚至创建可重复使用的Reducer来处理诸如分页等常见任务。

function visibilityFilter(state = 'SHOW_ALL', action) {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}

import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ visibilityFilter, todos })
let store = createStore(reducer)

欲了解更多信息,请点击这里


0

Redux对于不可变性需要有严格的纪律。我可以建议使用ng-freeze来让你发现任何意外的状态突变。


-1
据我所知,redux受flux启发。flux是一种类似于MVC(模型视图控制器)的架构。Facebook引入了flux,是因为在使用MVC时出现了可扩展性问题。因此,flux不是一种实现,它只是一个概念。实际上,redux就是flux的实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接