1 什么是Dva?

dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。

2 特性

  • 易学易用,仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用后更是降低为 0 API
  • elm 概念,通过 reducers, effects 和 subscriptions 组织 model
  • 插件机制,比如 dva-loading 可以自动处理 loading 状态,不用一遍遍地写 showLoading 和 hideLoading
  • 支持 HMR,基于 babel-plugin-dva-hmr 实现 components、routes 和 models 的 HMR

3 Dva中常见的概念

4 数据流向

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispatch 发起一个 action,如果是同步行为会直接通过 Reducers 改变 State ,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致(也是来自于开源社区)。

5 Models

State

type State = any

State 表示 Model 的状态数据,通常表现为一个 javascript 对象(当然它可以是任何值);操作的时候每次都要当作不可变数据(immutable data)来对待,保证每次都是全新对象,没有引用关系,这样才能保证 State 的独立性,便于测试和追踪变化。

在 dva 中你可以通过 dva 的实例属性 _store 看到顶部的 state 数据,但是通常你很少会用到:

const app = dva();
console.log(app._store); // 顶部的 state 数据

Action

type AsyncAction = any

Action 是一个普通 javascript 对象,它是改变 State 的唯一途径。无论是从 UI 事件、网络回调,还是 WebSocket 等数据源所获得的数据,最终都会通过 dispatch 函数调用一个 action,从而改变对应的数据。action 必须带有 type 属性指明具体的行为,其它字段可以自定义,如果要发起一个 action 需要使用 dispatch 函数;需要注意的是 dispatch 是在组件 connect Models以后,通过 props 传入的。

dispatch({type: 'add',
});

dispatch 函数

type dispatch = (a: Action) => Action

dispatching function 是一个用于触发 action 的函数,action 是改变 State 的唯一途径,但是它只描述了一个行为,而 dipatch 可以看作是触发这个行为的方式,而 Reducer 则是描述如何改变数据的。

在 dva 中,connect Model 的组件通过 props 可以访问到 dispatch,可以调用 Model 中的 Reducer 或者 Effects,常见的形式如:

dispatch({type: 'user/add', // 如果在 model 外调用,需要添加 namespacepayload: {}, // 需要传递的信息
});

Reducer

type Reducer<S, A> = (state: S, action: A) => S

Reducer(也称为 reducing function)函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。

Reducer 的概念来自于是函数式编程,很多语言中都有 reduce API。如在 javascript 中:

[{x:1},{y:2},{z:3}].reduce(function(prev, next){return Object.assign(prev, next);
})
//return {x:1, y:2, z:3}

在 dva 中,reducers 聚合积累的结果是当前 model 的 state 对象。通过 actions 中传入的值,与当前 reducers 中的值进行运算获得新的值(也就是新的 state)。需要注意的是 Reducer 必须是纯函数,所以同样的输入必然得到同样的输出,它们不应该产生任何副作用。并且,每一次的计算都应该使用immutable data,这种特性简单理解就是每次操作都是返回一个全新的数据(独立,纯净),所以热重载和时间旅行这些功能才能够使用。

Effect

Effect 被称为副作用,在我们的应用中,最常见的就是异步操作。它来自于函数编程的概念,之所以叫副作用是因为它使得我们的函数变得不纯,同样的输入不一定获得同样的输出。

dva 为了控制副作用的操作,底层引入了redux-sagas做异步流程控制,由于采用了generator的相关概念,所以将异步转成同步写法,从而将effects转为纯函数。至于为什么我们这么纠结于 纯函数,如果你想了解更多可以阅读Mostly adequate guide to FP,或者它的中文译本JS函数式编程指南。

Subscription

Subscriptions 是一种从  获取数据的方法,它来自于 elm。

Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。

import key from 'keymaster';
...
app.model({namespace: 'count',subscriptions: {keyEvent({dispatch}) {key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) });},}
});

6 Router

这里的路由通常指的是前端路由,由于我们的应用现在通常是单页应用,所以需要前端代码来控制路由逻辑,通过浏览器提供的 History API 可以监听浏览器url的变化,从而控制路由相关操作。

dva 实例提供了 router 方法来控制路由,使用的是react-router。

import { Router, Route } from 'dva/router';
app.router(({history}) =><Router history={history}><Route path="/" component={HomePage} /></Router>
);

7 Route Components

在组件设计方法中,我们提到过 Container Components,在 dva 中我们通常将其约束为 Route Components,因为在 dva 中我们通常以页面维度来设计 Container Components。

所以在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在/routes/目录下,而/components/目录下则是纯组件(Presentational Components)。

8 入门课

React 没有解决的问题

React 本身只是一个 DOM 的抽象层,使用组件构建虚拟 DOM。

如果开发大应用,还需要解决一个问题。

  • 通信:组件之间如何通信?
  • 数据流:数据如何和视图串联起来?路由和数据如何绑定?如何编写异步逻辑?等等

通信问题

组件会发生三种通信。

  • 向子组件发消息
  • 向父组件发消息
  • 向其他组件发消息

React 只提供了一种通信手段:传参。对于大应用,很不方便。

组件通信的例子

步骤1

class Son extends React.Component {render() {return <input/>;}
}class Father extends React.Component {render() {return <div><Son/><p>这里显示 Son 组件的内容</p></div>;}
}ReactDOM.render(<Father/>, mountNode);

看这个例子,想一想父组件如何拿到子组件的值。

步骤2

class Son extends React.Component {render() {return <input onChange={this.props.onChange}/>;}
}class Father extends React.Component {constructor() {super();this.state = {son: ""}}changeHandler(e) {this.setState({son: e.target.value});}render() {return <div><Son onChange={this.changeHandler.bind(this)}/><p>这里显示 Son 组件的内容:{this.state.son}</p></div>;}
}ReactDOM.render(<Father/>, mountNode);

看下这个例子,看懂源码,理解子组件如何通过父组件传入的函数,将自己的值再传回父组件。

数据流问题

目前流行的数据流方案有:

  • Flux,单向数据流方案,以 Redux 为代表
  • Reactive,响应式数据流方案,以 Mobx 为代表
  • 其他,比如 rxjs 等

到底哪一种架构最合适 React ?

目前最流行的数据流方案

截止 2017.1,最流行的社区 React 应用架构方案如下。

  • 路由: React-Router
  • 架构: Redux
  • 异步操作: Redux-saga

缺点:要引入多个库,项目结构复杂。

dva 是什么

dva 是体验技术部开发的 React 应用框架,将上面三个 React 工具库包装在一起,简化了 API,让开发 React 应用更加方便和快捷。

dva = React-Router + Redux + Redux-saga

dva 应用的最简结构

import dva from 'dva';
const App = () => <div>Hello dva</div>;// 创建应用
const app = dva();
// 注册视图
app.router(() => <App />);
// 启动应用
app.start('#root');

数据流图

核心概念

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

State 和 View

State 是储存数据的地方,收到 Action 以后,会更新数据。

View 就是 React 组件构成的 UI 层,从 State 取数据后,渲染成 HTML 代码。只要 State 有变化,View 就会自动更新。

Action

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

{type: 'click-submit-button',payload: this.form.data
}

connect 方法

connect 是一个函数,绑定 State 到 View。

import { connect } from 'dva';function mapStateToProps(state) {return { todos: state.todos };
}
connect(mapStateToProps)(App);

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

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

dispatch 方法

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

dispatch({type: 'click-submit-button',payload: this.form.data
})

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

connect 的数据从哪里来?

dva 应用的最简结构(带 model)

// 创建应用
const app = dva();// 注册 Model
app.model({namespace: 'count',state: 0,reducers: {add(state) { return state + 1 },},effects: {*addAfter1Second(action, { call, put }) {yield call(delay, 1000);yield put({ type: 'add' });},},
});// 注册视图
app.router(() => <ConnectedApp />);// 启动应用
app.start('#root');

数据流图 1

数据流图 2

app.model

dva 提供 app.model 这个对象,所有的应用逻辑都定义在它上面。

const app = dva();// 新增这一行
app.model({ /**/ });app.router(() => <App />);
app.start('#root');

Model 对象的例子

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

Model 对象的属性

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

Reducer

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

一些例子:

// count +1
function add(state) { return state + 1; }// 往 [] 里添加一个新 todo
function addTodo(state, action) { return [...state, action.payload]; }// 往 { todos: [], loading: true } 里添加一个新 todo,并标记 loading 为 false
function addTodo(state, action) {return {...state,todos: state.todos.concat(action.payload),loading: false};
}

Effect

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

function *addAfter1Second(action, { put, call }) {yield call(delay, 1000);yield put({ type: 'add' });
}

Generator 函数

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

call 和 put

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

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

原文链接-DvaJs官网:https://dvajs.com/guide/

写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,希望尽自己的努力,做到更好,大家一起努力进步!

如果有什么问题,欢迎大家评论,一起探讨,代码如有问题,欢迎各位大神指正!

给自己的梦想添加一双翅膀,让它可以在天空中自由自在的飞翔!

React应用框架DvaJs入门相关推荐

  1. React 应用框架:DvaJS

    最近在学习react相关的东西,记录一下react 开发中,组件通信和数据流的应用框架 dva: 一.dva是什么?要解决的问题? React 本身只是一个 DOM 的抽象层,使用组件构建虚拟 DOM ...

  2. react ui框架_顶级React组件库推荐

    作者丨Max Rozen 译者丨王强 策划丨小智 转发链接:https://mp.weixin.qq.com/s/-vRr8Qd8DCNiza09eZjmbQ 本文最初发布于 maxrozen.com ...

  3. React学习笔记:入门案例

    React学习笔记:入门案例 React 起源于 Facebook 内部项目,因为市场上所有 JavaScript MVC 框架都不令人满意,公司就决定自己写一套,用来架设 Instagram 的网站 ...

  4. 必须收藏!这13个优秀React JS框架,没用过就很离谱!

    如果你正在使用React.js或React Native创建用户界面,可以试一试本文推荐的这些框架.   React.js和React Native是流行的用户界面(UI)开发平台,且都是开源技术.在 ...

  5. 视频教程-React 全家桶从入门到实战到源码-其他

    React 全家桶从入门到实战到源码 上市公司前端开发工程师,专注于 React 技术栈,对 React 全家桶从 react-router 路由到 Redux 状态管理工具再到 webpack 打包 ...

  6. 视频教程-新React+VUE前端教程入门到精通-Vue

    新React+VUE前端教程入门到精通 10年以上开发经验,曾经是八维教育实训主任,千峰教育高级HTML5前端讲师,尚品中国创始人.现任程序思维创始人.曾和大厂.国企等大型企业合作开发项目.百余客户, ...

  7. 视频教程-React.js框架技术-Java

    React.js框架技术 软通动力教育集团简称软通大学,依托软通动力在技术服务领域的多方位解决方案能力,采用先进的教学理念和模式,直通高校和城市,开展干部培养,文化落地,初级资源培训,培训需求对接,专 ...

  8. DvaJS 入门, 快速上手Dva

    为什么要使用Dva? React 没有解决的问题 React 本身只是一个 DOM 的抽象层,使用组件构建虚拟 DOM. 如果开发大应用,还需要解决一个问题. 通信:组件之间如何通信? 数据流:数据如 ...

  9. 从Preact了解一个类React的框架是怎么实现的(一): 元素创建

    首先欢迎大家关注我的掘金账号和Github博客,也算是对我的一点鼓励,毕竟写东西没法获得变现,能坚持下去也是靠的是自己的热情和大家的鼓励. 之前分享过几篇关于React的文章: React技术内幕: ...

最新文章

  1. Linux下使用diff和patch制作及打补丁(已经实践可行!)
  2. Azure Neural TTS能让AI语音自然逼真到什么程度?
  3. 整理Java基础知识--输出格式知识
  4. 你应该知道的grep命令
  5. 简述用决策表设计测试用例的步骤_决策表快速入门
  6. 服务器标记“asp:ScriptManager”不明确。
  7. linux stdin STDIN_FILENO 区别
  8. python 透视变换补边
  9. 数据挖掘十大经典算法之——KNN 算法
  10. Keepalived - Keepalived 实现 tomcat双机热备
  11. python:数据操作小技巧
  12. ubuntu 的QT4的qmake失败的处理方法
  13. 【复杂系统迁移 .NET Core平台系列】之迁移项目工程
  14. 第一章 概率论的基本概念
  15. python打印九九加法表_Python小脚本
  16. python基础(2)
  17. Win10 UWP系列:关于错误 0x80073CF9及一个小bug的解决
  18. 变量存储list python_Python变量类型(八)
  19. mysql 搜索_MySQL模糊搜索的几种姿势
  20. 水晶报表基础入门——6.交叉报表设计技术

热门文章

  1. 我是如何向老婆解释MapReduce的?
  2. [C++] OJ造数据程序
  3. python pop
  4. popstate_ios下popstate触发的问题
  5. 推荐的ADM平台整机
  6. 动态照片墙 python 实现_使用Python生成照片墙,利用,python
  7. 曼彻斯特编码 差分曼彻斯特编码 计算机网络
  8. 什么是js变量提升?
  9. 海格里斯仓储货架中心为你解惑:托盘式货架的选择和安装小细节有多重要
  10. android-揭秘热修复黑科技