首页 男生 其他 深入浅出React和Redux

3.2.1 Redux的基本原则

深入浅出React和Redux 程墨 5166 2021-04-06 02:29

  您可以在百度里搜索“深入浅出React和Redux 艾草文学(www.321553.xyz)”查找最新章节!

  

  3.2.1 Redux的基本原则

  2013年问世的Flux饱受争议,而2015年Dan Abramov提出了在Flux基础上的改进框架Redux,则是一鸣惊人,在所有Flux的变体中算是最受关注的框架,没有之一。

  Flux的基本原则是“单向数据流”,Redux在此基础上强调三个基本原则:

  ·唯一数据源(Single Source of Truth);

  ·保持状态只读(State is read-only);

  ·数据改变只能通过纯函数完成(Changes are made with pure functions)。

  让我们逐一解释这三条基本原则。

  1.唯一数据源

  唯一数据源指的是应用的状态数据应该只存储在唯一的一个Store上。

  我们已经知道,在Flux中,应用可以拥有多个Store,往往根据功能把应用的状态数据划分给若干个Store分别存储管理。比如,在上面的ControlPanel例子中,我们创造了CounterStore和SummaryStore。

  如果状态数据分散在多个Store中,容易造成数据冗余,这样数据一致性方面就会出问题。虽然利用Dispatcher的waitFor方法可以保证多个Store之间的更新顺序,但是这又产生了不同Store之间的显示依赖关系,这种依赖关系的存在增加了应用的复杂度,容易带来新的问题。

  Redux对这个问题的解决方法就是,整个应用只保持一个Store,所有组件的数据源就是这个Store上的状态。

  注意

  Redux并没有阻止一个应用拥有多个Store,只是,在Redux的框架下,让一个应用拥有多个Store不会带来任何好处,最后还不如使用一个Store更容易组织代码。

  这个唯一Store上的状态,是一个树形的对象,每个组件往往只是用树形对象上一部分的数据,而如何设计Store上状态的结构,就是Redux应用的核心问题,我们接下来会描述具体细节。

  2.保持状态只读

  保持状态只读,就是说不能去直接修改状态,要修改Store的状态,必须要通过派发一个action对象完成,这一点,和Flux的要求并没有什么区别。

  如果只看这个原则的字面意思,可能会让读者感觉有点费解,还记得那个公式吗?UI=render(state),我们已经说过驱动用户界面更改的是状态,如果状态都是只读的不能修改,怎么可能引起用户界面的变化呢?

  当然,要驱动用户界面渲染,就要改变应用的状态,但是改变状态的方法不是去修改状态上值,而是创建一个新的状态对象返回给Redux,由Redux完成新的状态的组装。

  这就直接引出了下面的第三个基本原则。

  3.数据改变只能通过纯函数完成

  这里所说的纯函数就是Reducer,Redux这个名字的前三个字母Red代表的就是Reducer。按照创作者Dan Abramov的说法,Redux名字的含义是Reducer+Flux。

  Reducer不是一个Redux特定的术语,而是一个计算机科学中的通用概念,很多语言和框架都有对Reducer函数的支持。就以JavaScript为例,数组类型就有reduce函数,接受的参数就是一个reducer,reduce做的事情就是把数组所有元素依次做“规约”,对每个元素都调用一次参数reducer,通过reducer函数完成规约所有元素的功能。

  下面是一个使用reducer函数的例子:

  [1, 2, 3, 4].reduce(function reducer(accumulation, item) {

  return accumulation + item

  }, 0);

  上面的代码中,reducer(注意不是reduce)函数接受两个参数,第一个参数是上一次规约的结果,第二个参数是这一次规约的元素,函数体是返回两者之和,所以这个规约的结果就是所有元素之和。

  在Redux中,每个reducer的函数签名如下所示:

  reducer(state, action)

  第一个参数state是当前的状态,第二个参数action是接收到的action对象,而reducer函数要做的事情,就是根据state和action的值产生一个新的对象返回,注意reducer必须是纯函数,也就是说函数的返回结果必须完全由参数state和action决定,而且不产生任何副作用,也不能修改参数state和action对象。

  让我们回顾一下Flux中的Store是如何处理函数的,代码如下:

  CounterStore.dispatchToken = AppDispatcher.register((action) => {

  if (action.type === ActionTypes.INCREMENT) {

  counterValues[action.counterCaption] ++;

  CounterStore.emitChange();

  } else if (action.type === ActionTypes.DECREMENT) {

  counterValues[action.counterCaption] --;

  CounterStore.emitChange();

  }

  });

  Flux更新状态的函数只有一个参数action,因为状态是由Store直接管理的,所以处理函数中会看到代码直接更新state;在Redux中,一个实现同样功能的reducer代码如下:

  function reducer(state, action) => {

  const {counterCaption} = action;

  switch (action.type) {

  case ActionTypes.INCREMENT:

  return {...state, [counterCaption]: state[counterCaption] + 1};

  case ActionTypes.DECREMENT:

  return {...state, [counterCaption]: state[counterCaption] - 1};

  default:

  return state

  }

  }

  可以看到reducer函数不光接受action为参数,还接受state为参数。也就是说,Redux的reducer只负责计算状态,却并不负责存储状态。

  我们会在后面的实例中详细解释这个reducer的构造。

  读到这里,读者可能会有一个疑问,从Redux的基本原则来看,Redux并没有赋予我们强大的功能,反而是给开发者增加了很多限制啊,开发者丧失了想怎么写就怎么写的灵活度。

  “如果你愿意限制做事方式的灵活度,你几乎总会发现可以做得更好。”

  ——John Carmark

  作为制作出《Doom》《Quake》这样游戏的杰出开发者,John Carmark这句话道出了软件开发中的一个真谛。

  在计算机编程的世界里,完成任何一件任务,可能都有一百种以上的方法,但是无节制的灵活度反而让软件难以维护,增加限制是提高软件质量的法门。 深入浅出React和Redux

目录
设置
手机
书架
书页
评论