dva模式下的redux应用

205 阅读5分钟

我正在参加「掘金·启航计划」

一、为什么使用redux

简单来说,redux是为了解决react组件间通信和组件间状态共享问题而提出的一种解决方案。

没有使用redux的情况,如果两个组件(非父子关系)之间需要通信的话,可能需要多个中间组件为他们进行消息传递,这样既浪费了资源,代码也会比较复杂。而通过redux即可将状态数据统一管理,在需要使用的组件中直接调用。

总结来说,当我们项目中存在以下场景,可以考虑使用redux

a. 某个组件的状态需要共享(A组件与B组件公用状态)

b. 某个状态需要在任何地方都可以拿到(分辨率等)

c. 一个组件需要改变全局状态(设置分辨率,主题等)

d. 一个组件需要改变另一个组件的状态(非父子组件间的联动)

二、什么是Redux

Redux是一个独立专门做状态管理的js库,作用是集中式管理react应用中多个组件共享的状态。

1. redux的三要素

image.png

(1) Store

Store就是保存数据的地方,你可以把它看成一个容器,整个应用只有一个Store。Store提供getState方法,生成当前时点的数据集合,也就是state。

(2) Action

我们知道,在react中,state与view是一一对应的,state的变化会导致view的变化。但是在redux中,用户不能直接接触到State,只能接触到view,所以如果希望改变state(store),就需要从view发出指令,告诉Store该发生变化了,这个指令就是Action。

Action是一个对象,其中type属性是必须的,它表示Action的名称,其他属性可以自定义,我们一般传递payload属性作为Action携带的具体参数。

Store.dispatch()是View发出Action的唯一方法,它接收一个Action对象作为参数,将它发送到Store。

(3) Reducer

Store在接收到Action后,为了使View发生更新,需要给出一个新的State,这个重新设置State的过程就是Reducer。

Reducer是一个纯函数,及在函数内部不涉及任何逻辑操作、任何接口调用、任何参数的调整,它的作用在于接收当前的state与Action,返回一个新的State。

2. redux的工作流

image.png

总结来说,redux的工作流是用户在组件中(View)发起修改State的指令(Action)-> Store接收指令,并调用Reducers中的方法返回新State -> Store接收到新的State,同步更新界面(View)

三、dva模式下的redux应用

原生的redux在实际使用的过程中会略显复杂,不易理解,所以dva封装了redux,减少了很多重复代码比如action/reducers等常量,简化了开发体验。

dva中最重要的概念就是--model,通过model的概念可以把一个模块/类型的模型状态管理起来,包含了同步更新State的Reducers,处理异步逻辑的effects等,这里我们结合具体项目案例讲解。

Umi框架中包含了dva模式。

Model

首先,我们建立models文件夹,umi会自动寻找命名为models的文件夹,再从中寻找model image.png

以global.ts为例,这里我们存放一些公共的状态,如分辨率信息

image.png

我们可以看到,在定义好接口信息后,我们会输出一个包含namespace,state,effects,reducers等属性的对象,他们各自的含义是:

namespace:表示在全局 state 上的 key

state:初始值,state 是储存数据的地方,收到 Action 以后,会更新数据。state 表示 Model 的状态数据,通常是一个对象(当然它可以是任何值);更新时每次都要当作不可变数据来对待,保证每次都是全新对象,没有引用关系,这样才能保证 state 的独立性,便于测试和追踪变化

reducers: 等同于 redux 里的 reducer,接收 action,同步更新 state,Reducer函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。在 dva 中,reducers 聚合积累的结果是当前 model 的 state 对象。通过 actions 中传入的值,与当前 reducers 中的值进行运算获得新的值(也就是新的 state)。需要注意的是 Reducer 必须是纯函数,所以同样的输入必然得到同样的输出,它们不应该产生任何副作用。

effects:处理异步动作,Effect 是一个 Generator 函数,内部使用 yield 关键字,标识每一步的操作(不管是异步或同步)。dva 提供多个 effect 函数内部的处理函数,比较常用的是 call 和 put。call:执行异步函数,把return传回来。put:发出一个 Action,类似于 dispatch,把参数传回来

image.png

组件中发起Action

image.png

image.png image.png

不管在函数式组件还是类组件中,如果我们希望使用或调用Action更新state,都需要接收dispatch参数,并通过connect方法将model与组件连接起来,如上图所示,我们在组件中拿到屏幕分辨率后,调用一个dispatch方法,传递Action参数,意义就是调用namespace是’global’的model中,reducers或effects中的updateMediaQueries方法,从而更新state。

 

组件中运用State

image.png

 

在具体组件中,我们仍然可以通过connect的方法,将model与组件连接。connect传入的第一个参数是一个函数,该函数返回一个对象,用于建立State到Props的映射关系。

image.png

如上图,mediaQueries实际存放在组件的props中,我们可以在组件中取到分辨率,通过useEffct方法也可以做到分辨率更新时组件实时更新。

  image.png