图解Redux

这里写图片描述


简介

有一点比Flux更令人困惑的是Flux和Redux之间的差异,而Redux正是Flux的灵感来源。 在本文将解释这两者之间的差异。

如果您还没有阅读关于Flux的最新文章,那么您应该先做阅读此篇文章图解Flux


为什么要改变Flux

Redux解决与Flux相同的问题,但另外还有一些问题。

就像Flux一样,Redux使应用程序的state更改变得更加可预测。 如果你想改变state,你必须启动一个action。 没有办法直接改变state,因为持有state(store)的东西只有一个getter,而不是setter。 Flux和Redux的这些基础知识非常相似。

那么为什么还要有这个不同的模式? Redux的创造者Dan Abramov看到了一个改进Flux的机会。 他想要更好的开发工具。 他看到,如果将内部一些部件转移,就可以制作出更好的开发工具,同时仍然具有Flux给你的可预测性。

他希望热重新加载和时间旅行调试(hot reloading and time travel debugging)。 但是有一些问题使得开发人员使用Flux时很难做到。

问题1:商店代码不能在不消除状态的情况下重新加载


在Flux中,store包含两件事:

  • 更改逻辑的state
  • 当前的state

将这两个放在同一个对象上是热重载问题。 当您重新加载存储对象以查看新状态所带来的逻辑更改时,您将失去store所持有的state。 另外,你会弄乱将store与系统其余部分之间的事件订阅。
这里写图片描述


解决方法

分开这两个功能。 有一个对象持有state。 该对象不会重新加载。 有另一个对象包含所有会更改逻辑的state。 这个对象可以重新加载,因为它不必担心任何state。
这里写图片描述


问题2:state被每一个action重写

在时间旅行调试中,您会跟踪state对象的每个版本。 这样,你可以回到更早的state。
每次state更改时,都需要将旧state添加到以前state对象的数组中。 但由于JavaScript的工作方式,简单的将该变量添加到数组中将无法工作。 这不会创建对象的快照,只会创建一个指向同一对象的新指针。

为了使它工作,每个版本都需要是一个完全独立的对象,这样你才不会意外地改变过去的版本。
这里写图片描述


解决方法

当一个action进入store时,不要通过改变state来处理它。 相反,请复制state并对副本进行更改。
这里写图片描述


问题3:没有好的地方供第三方插件使用

当你制作开发者工具时,你需要能够更范型般的编写它们。 用户应该能够放下工具,而不必修改自己的代码以适应它

为了达到这个目的,你需要在某个地方拓展一下。

一个例子是日志记录。 假设你想要console.log()每一个动作,然后是console.log()它所产生的状态。 在Flux中,您必须订阅dispatcher的更新以及每个store的更新。 但这是自定义代码,不是第三方模块可以轻松完成的事情。
这里写图片描述


解决方法

可以很容易地将系统的一部分包装在其他对象中。 这些对象将其功能添加到的对象上。 您通常可以在“增强器”或“修饰器”对象以及中间件中看到这种拓展。

另外,使用树来构造state更改逻辑。 这使得store只发出一个事件来通知View state已经改变。 这个事件发生在整个state树被处理之后。
这里写图片描述

注意:有了这些问题和解决方案,本文将专注于开发人员工具用例。 这些更改也有助于其他用例。 最重要的是,Redux和Flux还有其他不同之处。 例如,Redux还可以减少样板,并且可以更轻松地在store中重新使用逻辑。 这里列出了Redux的其他一些好处。

所以让我们看看Redux如何让这些事情成为可能。


认识一下演员的新角色

从Flux到Redux,角色的转换有点变化。


Action Creator

动作创造者就像一个电报操作员。 它会为您设置格式。

Redux保留Flux的Action Creator。 无论何时你想改变应用程序的state,你都会发起一个action。 这是state改变的唯一方式。

正如图解Flux中所说的,我认为Action Creator是电报操作员。 Action Creator基本知道你想发送什么消息,然后Action Creator以一种其他系统可以理解的方式进行格式化。

与Flux不同,Redux中的Action Creator不会将动作发送给Dispatcher。 相反,他们返回格式化的操作对象。


Store

这里写图片描述

我把Flux的store描述为一个充满控制欲的长官。所有state变化必须由store亲自做出,并且必须通过action,而不是直接改变。 Redux的store仍然是一个充满控制欲的长官,但它有点不同。
在Flux中,您可以拥有多个store。每家store都有自己的小地方,并且完全控制。它持有了它的一小部分state,并具有改变这一小部分state的逻辑。

Redux的store更像delegate。并且它必须更像。在Redux,只有一个store……所以如果它自己做了所有事情,它将会承担太多的工作。

相反,它需要保留整个state树。然后它将委派确定需要发生状态变化的工作。由根reducers领导的reducers负责完成这项任务。

你可能已经注意到没有dispatcher。这是因为,在一点权力抢夺中,store也接管了dispatcher。


Reducers

这里写图片描述
当store需要知道行为如何改变state时,它会询问reducer。根reducer根据state对象的key对state进行管理与切片。它将每一片state传递给知道如何处理它的reducer。

我认为reducer是一个白领阶层,他们对复印(复制)有些过分热情。他们不想搞乱任何东西,所以他们不会改变已经传递给他们的state。相反,他们制作副本并对副本进行所有更改。

这是Redux的主要想法之一。state对象不被直接修改的。相反,每个切片都被复制,然后所有的切片被组合成一个新的state对象。

reducer将它们的副本传回到根reducer,它将副本粘贴在一起以形成更新的state对象。然后,根reducer将新的state对象发送回store,并且商店使其成为新的官方状态。

如果你有一个小应用程序,你可能只有一个reducer复制整个state对象并进行更改。或者如果你有一个大的应用程序,你可能会有一个完整的的reducer树。这是Flux和Redux的另一个区别。在Flux中,store不一定彼此连接,并且它们具有扁平结构。在Redux中,reducer处于分水岭状态。该层次结构可以根据需要具有尽可能多的级别,就像组件层次结构一样。


View:smart 和 dumb组件

这里写图片描述
Flux拥有controller views和常规View。controller views充当中层管理者,管理store与其子View之间的通信。

在Redux中,有一个类似的概念:smart 和 dumb组件。smart组件是管理者。不过,他们遵循比controller views更多的规则:

  • 智能组件负责这些操作。如果他们下面的哑组件需要触发动作,智能组件会通过道具传递一个函数。愚蠢的组件可以将其视为回调。
  • smart组件没有自己的CSS样式。
  • smart组件很少发出自己的DOM。相反,他们安排了 dumb组件,这些组件处理DOM元素的布局。

dumb组件不直接依赖于cation文件,因为所有action都可以通过props传入。这意味着dumb组件可以在具有不同逻辑的不同应用程序中重用。他们还包含他们需要看起来相当好的样式(尽管您可以允许自定义样式 - 只需接受样式props并将其合并到默认样式中即可)。


视图图层绑定

这里写图片描述
要将store连接到View,Redux需要一些帮助。 它需要一些东西将两者结合在一起。 这被称为视图层绑定(view layer binding)。 如果你使用React,这是react-redux。

视图层绑定有点像View树的IT部门。 它确保所有组件都可以连接到store。 它还需要处理大量的技术细节,以便其他层次结构不必理解它们。

视图层绑定引入了三个概念:

  • Provider组件:这包含在组件树中。 它使得根组件的子项可以很容易地使用connect()连接到store。
  • connect():这是react-redux提供的一个函数。 如果一个组件想要获得state更新,它将使用connect()进行自我封装。 然后,connect功能将使用selector设置它的连接。
  • selector:这是你写的一个函数。 它指定组件需要的state的哪些部分作为属性。

根组件

这里写图片描述

所有React应用程序都有根组件。 这只是组件层次结构顶层的组件。 但在Redux应用程序中,此组件承担更多责任。

它所扮演的角色有点像C级高管。 它使所有的团队都可以处理这项工作。 它创建store,告诉它使用什么reducer,并将视图图层绑定View组合在一起。

除此之外,根组件在初始化应用程序后不插手任何事。 它不会时时刻刻担忧重绘。 它让视图图层绑定协助它下面的组件完成上述事情。


它们如何在一起工作?

我们来看看这些部分是如何协同工作来创建一个功能正常的应用

开始

首先在应用启动时:应用程序初始化只发生一次。

  • 准备好store。 根组件创建store,使用createStore()告诉它要使用哪个根reducer。 这根reducer已经有一组reducer。 它使用combineReducers()组装了这个reducer团队。

这里写图片描述


  • 设置store和组件之间的通信。 根组件使用provider组件包装其子组件,并在store和提供程序之间建立连接。

Provider创建更新组件的网络。 smart组件使用connect()连接到网络。 这确保他们会得到状态更新。
这里写图片描述


  • 准备action的回调函数。 为了让dumb组件更容易处理动作,smart组件可以使用bindActionCreators()来设置action回调函数。 这样,他们可以将回调函数传递给dumb组件。 格式化后,该动作将自动被分派。
    这里写图片描述

数据流

现在应用程序已经建立好了,用户可以开始与它进行交互。 让我们触发一个action来查看数据流。
这里写图片描述


  • 1.View请求一个action。 action creator对其进行格式化并将其返回。
    这里写图片描述

  • 该action是自动分派的(如果在设置中使用bindActionCreators()),或者View分派action。
    这里写图片描述

  • store收到该action。 它将当前state树和action发送到根reducer。
    这里写图片描述

  • 根reducer将state切成片。 然后它将每个切片传递给知道如何处理它的子reducer。

这里写图片描述


  • 子reducer复制切片并对该副本进行更改。 它将切片的副本返回到根reducer。
    这里写图片描述

  • 一旦所有的子reducer都返回它们的切片副本,根reducer将它们全部粘贴在一起以形成整个更新后的state树,并将其返回到store。 store用新的state树代替旧的state树。
    这里写图片描述

  • store告诉view layer binding有新的state。
    这里写图片描述

  • view layer binding要求store发送新的state。
    这里写图片描述

  • view layer binding触发重新渲染。
    这里写图片描述

结尾

以上就是图解Redux, 希望能帮助到你!

原文

猜你喜欢

转载自blog.csdn.net/wanywhn/article/details/79944513