redux和dva
阅读原文时间:2023年07月10日阅读:1

实习的时候,公司使用的是react,react说实话生态学的还不是很完善,就暂时先不做跟react相关的博客,等以后学好了react全家桶之后,专门再总结一下react的内容

这两天看了公司的alita和dva,具体项目还没上手,但是对dva很感兴趣,一方面因为dva名字的由来,另一方面刚好在看redux的内容。

在讲redux的时候,不得不把vuex拿出来讲讲,说实话,vuex很久之前学的了,vue是我前端框架第一次接触的,vue的方便性也让我很喜爱,但是身为一个前端攻城狮怎么能不学其他框架呢,趁着在公司实习的日子里,把react的学习提上日程

扯远了,回到redux和vuex中。redux是一个状态数据的管理库,它可以用在react,也可以用在vue中,但是vue自己有一个vuex,兼容性更好,所以更大多数redux用在react的项目中。

学习vuex的时候,与现在的redux做对比,很清晰能比较出来,vuex比redux简单

下图是vuex的工作流程原理

VueX是数据管理框架,在之前我们vue里面的数据是data,父子组件,provide等等传递 在vue工程里面,数据就不是组件级别的创建,而是页面级别的创建了

VueX创建了全局的仓库,在vuex的state中,存放在全局的数据。我们使用vuex提供的store对象的state属性,来获取全局的数据

export default{
  name:'Home',
  computed:{
    myName(){
      return this.$store.state.name;
    }
  }
}

我们如何修改全局的数据?Vuex不允许我们直接修改全局的数据

因此我们要 调用$store里面一个方法叫做dispatch,他去派发一个action,这个action的名字叫做change 在createStore里就有一个action接收派发而来的change,执行这个change方法。在这个方法中提交一个commit触发一个mutation,在mutations里面接收触发而来方法并执行,在该方法中我们就可以修改数据

vuex的工作流程就是,组件之间使用dispatch去派发一个action,vuex中主要有三个属性action,commit,state用来操作管理数据。

actions感知到组件所派发的action,执行action对应参数的方法,提交一个commit去触发mutation,mutation中执行收到的commit的参数方法。从而修改state数据,而这个state数据就是全局的数据仓库

在最近的学习中,我接触到了redux,说实话,redux复杂程度高于vuex。

react整个应用中会存在很多个组件,每个组件的state是由自身进行管理,包括组件定义自身的state、组件之间的通信通过props传递、使用Context实现数据共享

将所有的状态进行集中管理,当需要更新状态的时候,仅需要对这个管理集中处理,而不用去关心状态是如何分发到每一个组件内部的

redux就是一个实现上述集中管理的容器,遵循三大基本原则:

  • 单一数据源
  • state 是只读的
  • 使用纯函数来执行修改

redux要求我们把数据都放在 store公共存储空间

一个组件改变了 store 里的数据内容,其他组件就能感知到 store的变化,再来取数据,从而间接的实现了这些数据传递的功能

React Components (组件)需要获取一些数据, 然后它就告知 Store 需要获取数据,这就是 Action Creactor , Store 接收到之后去 Reducer 查一下, Reducer 会告诉 Store 应该给这个组件什么数据

如何使用?

创建一个store

import { createStore } from 'redux' // 引入redux
const store = createStore() // 创建数据的公共存储区域

还需要创建一个记录本去辅助管理数据,也就是reduecer,本质就是一个函数,接收两个参数state,action,返回state

// 设置默认值
const initialState = {
counter: 0
}

const reducer = (state = initialState, action) => {
}

将记录本传递给store,两者建立连接,获取store里面的数据,则通过store.getState()来获取当前state

const store = createStore(reducer)
store.getState()

那么如何更改store中的数据呢?

是通过dispatch来派发action,通常action中都会有type属性,还有传入的更改数据。

type属性代表这个action所要做的操作

store.dispatch({
type: "ADD_NUMBER",
number: 5
})

ruducer中处理所要进行操作,使用swich去接收不同action所代表的操作方法

const reducer = (state = initialState, action) => {
switch (action.type) {
case "INCREMENT":
return {…state, counter: state.counter + 1};
case "DECREMENT":
return {…state, counter: state.counter - 1};
case "ADD_NUMBER":
return {…state, counter: state.counter + action.number}
default:
return state;
}
}

注意,reducer是一个纯函数,不需要直接修改state

这样派发action之后,既可以通过store.subscribe监听store的变化,如下:

store.subscribe(() => {
console.log(store.getState());
})

小结

  • createStore可以帮助创建 store
  • store.dispatch 帮助派发 action , action 会传递给 store
  • store.getState 这个方法可以帮助获取 store 里边所有的数据内容
  • store.subscrible 方法订阅 store 的改变,只要 store 发生改变, store.subscrible 这个函数接收的这个回调函数就会被执行

在React项目中,会搭配react-redux进行使用

何为react-redux?

如下图

在react-redux中,我们将UI组件去除掉redux的操作,将redux的操作全部放在容器组件身上

容器组件向redux进行数据获取和更改,通过props将数据传递给UI组件,UI组件也通过props告知容器组件要对redux中的数据进行何样的操作

容器组件用以专门向reduxi请求修改状态,存在containers文件夹里面

UI组件无法向redux去修改,存在component文件夹里面

connet是一个函数,这个函数调用的返回值依旧是一个函数 ,返回值的函数让容器组件与UI组件进行关联,从而通过props进行组件间的通信。

const CountContainer=connect()(CountUI)

connect在第一次调用的时候要传入两个参数,传入的两个参数必须是函数 一个是redux中所保存的状态,另一个就是操作状态的方法。简写如下

function a(){
return {n:900}
}

function b(){
return {jia:(num)=>{dispatch({

type: "ADD_NUMBER",
number: 5

})}}
}

export default connect(a,b)(CountUI)

a函数返回的对象key作为UI组件的props的key,value作为UI组件的props的value,以供UI组件接收到state

b函数返回的对象实际上向redux派生一个action,告知redux对state中的数据进行何种操作

容器组件的两个方法:mapStateToProps和mapDispatchToProps.

这是官方给的名称,为了好理解上面的代码使用a,b简述。实际使用以官方文档为主

export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

回到今天所学习到的新框架——dva

dva 好像就是redux的一些轻量级应用整合,简化了API,让开发更方便,但果然这是我自己的理解。

  • State:一个对象,保存整个应用状态
  • View:React 组件构成的视图层
  • Action:一个对象,描述事件
  • connect 方法:一个函数,绑定 State 到 View
  • dispatch 方法:一个函数,发送 Action 到 State

不难发现,其本质和redux一样,只不过dva让redux的操作更加的方便简洁,提高了我们的开发效率。

Action 是用来描述 UI 层事件的一个对象。

connect 方法返回的也是一个 React 组件,也是称为容器组件。因为它是原始 UI 组件的容器,即在外面包了一层 State。

connect 方法传入的第一个参数是 mapStateToProps 函数,mapStateToProps 函数会返回一个对象,用于建立 State 到 Props 的映射关系。

dispatch 是一个函数方法,用来将 Action 发送给 State。

dispatch 方法从哪里来?被 connect 的 Component 会自动在 props 中拥有 dispatch 方法。

其实dva内容和react-redux是一样的原理,只不过为了开发速度,dva封装的API使得操作redux更为便捷

dva中有model对象,这个对象是我第一次遇到的,在这个对象中,封装这对redux中的各种操作

model最简结构

export default {
namespace: 'count',
state: 0,
reducers: {
add(state) {
return state + 1;
},
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
};

  • namespace: 当前 Model 的名称。整个应用的 State,由多个小的 Model 的 State 以 namespace 为 key 合成
  • state: 该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出
  • reducers: Action 处理器,处理同步动作,用来算出最新的 State
  • effects:Action 处理器,处理异步动作

Reducer 是 Action 处理器,用来处理同步操作,可以看做是 state 的计算器。它的作用是根据 Action,从上一个 State 算出当前 State。

Action 处理器,处理异步动作,基于 Redux-saga 实现。Effect 指的是副作用。根据函数式编程,计算以外的操作都属于 Effect,典型的就是 I/O 操作、数据库读写。

Effect 是一个 Generator 函数,内部使用 yield 关键字,标识每一步的操作(不管是异步或同步)。

dva 提供多个 effect 函数内部的处理函数,比较常用的是 call 和 put

  • * call:执行异步函数
    • put:发出一个 Action,类似于 dispatch

我们约定当 src/models 下存在 dva 的 models 文件时,会被自动加载到项目中。 即约定了存在即生效,因此我们约定仅在这个文件夹下存放 dva 的 models 文件,虽然存放其他的文件会被框架自动过滤忽略,但是在这个目录存放其他文件会增加理解的心智负担,建议不要存放无关的文件。且为了管理方便,一般将文件名和 models 的 namespace 一一对应,不仅可以直观的找到相应的 models ,而且能够保证不会存在 models 冲突的问题,因为文件系统本身就不允许同名文件。

时间不早,先休息,后面将会针对dva操作redux的具体进行总结,在这个总结中我们可以很直白的看出dva与redux操作上的简易程度

宣传下自己的网站mishi-blog.com

尚在襁褓中的一个网站。