dva01-初识

news2024/11/28 12:41:00

背景

React 本身只是一个 DOM 的抽象层,使用组件构建虚拟 DOM。如果开发大应用,还需要解决一个问题。

  • 通信React 只提供了一种传参手段,后续数据变化非常麻烦,无法适用于大应用。
  • 数据流:每次要更新数据,都要一层层传递,在页面交互复杂的情况下,无法对数据进行管控。

有没有一种方式,有个集中的地方去管理数据,集中处理数据的接收,修改和分发,目前流行的数据流方案有:

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

dva 将上面三个 React 工具库包装在一起,简化了 API,让开发 React 应用更加方便和快捷。
dva = React-Router + Redux + Redux-saga。

工具版本

名称版本
npm6.14.16
nodev14.19.0
dva2.4.1

初见 dva

//安装脚手架
$ npm install dva-cli@0.10.1 -g
//创建文件夹
$ dva new dva-react
//确认即可

通过 npm 安装 antd 和 babel-plugin-import 。babel-plugin-import 是用来按需加载 antd 的脚本和样式的,详见 repo 。

npm install antd babel-plugin-import --save

编辑 .webpackrc,使 babel-plugin-import 插件生效

{
+  "extraBabelPlugins": [
+    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
+  ]
}

定义路由

我们要写个应用来先显示产品列表。首先第一步是创建路由,路由可以想象成是组成应用的不同页面。

//dva-react/src/router.js
import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import Products from './routes/Products';
function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={Products} />
      </Switch>
    </Router>
  );
}
export default RouterConfig;

编写 component

随着应用的发展,你会需要在多个页面分享 UI 元素 (或在一个页面使用多次),在 dva 里你可以把这部分抽成 component 。我们来编写一个 ProductList component,这样就能在不同的地方显示产品列表了。

// dva-react/src/components/ProductList.js
import React from 'react';
import PropTypes from 'prop-types';
import { Table, Popconfirm, Button } from 'antd';

const ProductList = ({ onDelete, products }) => {
  const columns = [{
    title: 'Name',
    dataIndex: 'name',
  }, {
    title: 'Actions',
    render: (text, record) => {
      return (
        <Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
          <Button>Delete</Button>
        </Popconfirm>
      );
    },
  }];
  return (
    <Table
      dataSource={products}
      columns={columns}
    />
  );
};

ProductList.propTypes = {
  onDelete: PropTypes.func.isRequired,
  products: PropTypes.array.isRequired,
};
export default ProductList;

定义 model

完成 UI 后,现在开始处理数据和逻辑。dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions 。

//dva-react/src/models/products.js
export default {
  namespace: 'product',
  state: [],
  subscriptions: {
    setup({ dispatch, history }) {  // eslint-disable-line
    },
  },

  effects: {
    *fetch({ payload }, { call, put }) {  // eslint-disable-line
      yield put({ type: 'save' });
    },
  },

  reducers: {
    save(state, action) {
      return { ...state, ...action.payload };
    },
    delete(state, { payload: id }) {
      return state.filter(item => item.id !== id);
    },
  },
};

  • namespace 表示在全局 state 上的 key
  • state 是初始值,在这里是空数组
  • reducers 等同于 redux 里的 reducer,接收 action,同步更新 state

绑定 model

到这里,我们已经单独完成了 model 和 component,那么他们如何串联起来呢?dva 提供了 connect 方法。如果你熟悉 redux,这个 connect 就是 react-redux 的 connect 。

//dva-react/src/routes/ProductRoute.js
import React from 'react';
import {connect } from 'dva';
import ProductList from '../components/ProductList';

const ProductRoute = ({ dispatch, product }) => {
  
  function handleDelete(id) {
    dispatch({
      type: 'product/delete',
      payload: id,
    });
  }
  return (
    <div>
      <h2>List of Products</h2>
      <ProductList onDelete={handleDelete} products={product} />
    </div>
  );
};

// export default Products;
export default connect(({dispatch,product }) => ({
  dispatch,product
}))(ProductRoute);

我们还需要给这个model一些初始化数据:

//dva-react/src/index.js
// const app = dva();
const app = dva({
  initialState: {
    product: [
      { name: 'dva', id: 1 },
      { name: 'antd', id: 2 },
    ],
  },
});

启动项目界面如下所示:
在这里插入图片描述
当我们在组件ProductList.js点击删除按钮(目前就这个功能)确认后,会触发onDelete方法,由react知识可知,该方法来源于ProductRoute中。在ProductRoute我们定义了一个handleDelete方法,在方法里面使用了dispatch 函数将 Action 发送给 State。方法中type: 'product/delete'第一个product是一个namespace的值,delete表示一个具体的处理器方法。

相识 dva

数据流向

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispatch 发起一个 action,如果是同步行为会直接通过 Reducers 改变 State ,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致(也是来自于开源社区)。
在这里插入图片描述
在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在/routes/目录下,而/components/目录下则是纯组件(Presentational Components),对比前面示例我们可以得出,ProductList.jsProductRoute.jsproducts.js分别对应纯组件RouteComponentModel

model 组成

namespace

每一个model拥有一个唯一的标识,如下所示:
在这里插入图片描述

State

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

Reducers

Action 处理器,处理同步动作,用来算出最新的 State。Reducer(也称为 reducing function)函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。在 dva 中,reducers 聚合积累的结果是当前 model 的 state 对象。通过 actions 中传入的值,与当前 reducers 中的值进行运算获得新的值(也就是新的 state)。需要注意的是 Reducer 必须是纯函数,所以同样的输入必然得到同样的输出,它们不应该产生任何副作用。并且,每一次的计算都应该使用immutable data,这种特性简单理解就是每次操作都是返回一个全新的数据(独立,纯净),所以热重载和时间旅行这些功能才能够使用。
在这里插入图片描述

Effects

Action 处理器,处理异步动作。Effect被称为副作用,在我们的应用中,最常见的就是异步操作。它来自于函数编程的概念,之所以叫副作用是因为它使得我们的函数变得不纯,同样的输入不一定获得同样的输出。dva 为了控制副作用的操作,底层引入了redux-sagas做异步流程控制,由于采用了generator的相关概念,所以将异步转成同步写法,从而将effects转为纯函数。
在这里插入图片描述

Subscription

Subscriptions 是一种从 源 获取数据的方法,它来自于 elm。Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。如下所示监听当前路径是否是/,否则打印*
在这里插入图片描述

图解dva

React 表示法

在这里插入图片描述
按照 React 官方指导意见, 如果多个 Component 之间要发生交互, 那么状态(即: 数据)就维护在这些 Component 的最小公约父节点上, 也即是 <App/> <TodoList/> <Todo/> 以及<AddTodoBtn/> 本身不维持任何 state, 完全由父节点<App/> 传入 props 以决定其展现, 是一个纯函数的存在形式, 即: PureComponent

Redux 表示法

在这里插入图片描述
与图一相比, 几个明显的改进点:

  • 状态及页面逻辑从 里面抽取出来, 成为独立的 store, 页面逻辑就是 reducer
  • 及都是 Pure Component, 通过 connect 方法可以很方便地给它俩加一层 wrapper 从而建立起与 store 的联系: 可以通过 dispatch 向 store 注入 action, 促使 store 的状态进行变化, 同时又订阅了 store 的状态变化, 一旦状态有变, 被 connect 的组件也随之刷新
  • 使用 dispatch 往 store 发送 action 的这个过程是可以被拦截的, 自然而然地就可以在这里增加各种 Middleware, 实现各种自定义功能, eg: logging

这样一来, 各个部分各司其职, 耦合度更低, 复用度更高, 扩展性更好。

加入 Saga

在这里插入图片描述
上面说了, 可以使用 Middleware 拦截 action, 这样一来异步的网络操作也就很方便了, 做成一个 Middleware 就行了, 这里使用 redux-saga 这个类库, 举个栗子:

  • 点击创建 Todo 的按钮, 发起一个type=addTodo 的 action
  • saga 拦截这个 action, 发起 http 请求, 如果请求成功, 则继续向 reducer 发一个 type=addTodoSucc 的 action, 提示创建成功, 反之则发送 type=addTodoFail 的 action 即可。

图解dva

有了前面的三步铺垫, Dva 的出现也就水到渠成了, 正如 Dva 官网所言, Dva 是基于 React + Redux + Saga 的最佳实践沉淀, 做了 3 件很重要的事情, 大大提升了编码体验:

  1. 把 store 及 saga 统一为一个 model 的概念, 写在一个 js 文件里面
  2. 增加了一个 Subscriptions, 用于收集其他来源的 action, eg: 键盘操作
  3. model 写法很简约, 类似于 DSL 或者 RoR, coding 快得飞起✈️
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ACE C++网络通信框架深入解析ACE_Message_Block消息类

前言 我所见到最好消息包的接口设计莫过于ACE_Message_Block了。 为什么这样说呢&#xff1f; 对于它的API说明&#xff0c;我最初仅想在它的基础上提供注释说明&#xff0c;而不想多言其它&#xff0c;因为无需多言其他。 不过&#xff0c;后来还是补充两个图&#xff0c;以…

后台搭建常用方式及常用的插件

利用脚手架创建项目 create-vite 是一个快速生成主流框架基础模板的工具,安装后启动预设创建项目 使用NPM&#xff1a; npm create vitelatest 使用Yarn: yarn create vite 使用PNPM: pnpm create vite 开始 | Vite 官方中文文档 create-vue&#xff0c;是 Vue 官方的项目脚…

Flume工作原理 安装配置

目录 简介 主要功能 日志收集 数据处理 工作原理 Flume架构 安装 拷贝压缩包 解压 改名 修改配置文件 安装nc&#xff08;netcat&#xff09; 安装telnet协议 应用 应用一&#xff1a;实时监听 新建netcat-logger.conf文件 开启端口监听方式一 访问主机 开启…

flume安装与配置

目录 flume描述 flume用途 flume基本组件 配置flume 搭建环境&#xff1a; 解压flume安装包将其放入到opt/soft目录 在/opt/soft目录下将apache-flume-1.9.0-bin.tar.gz 改名为flume190 到/opt/soft/flume190/conf目录中将临时配置文件flume-env.sh.template拷贝为配置文…

香港酒店模拟分析项目报告--使用tableau、python、matlab

转载请标记本文出处 软件&#xff1a;tableau、pycharm、关系型数据库&#xff1a;MySQL 数据大量分析考虑电脑性能的情况。 文章目录前言一、爬虫是什么&#xff1f;二、使用tableau数据可视化1.引入数据1.1 制作直方图-各地区酒店数量条形图1.2 各地区酒店均价1.3 价格等级堆…

Idea+maven+spring-cloud项目搭建系列--11-3 dubbo限流和熔断

前言: dubbo 作为rpc 通信组件&#xff0c;在使用过程中&#xff0c;如何避免服务提供端被多个消费端撑爆&#xff0c;消费端如何避免因为服务端的故障造成结果响应超时。 1 服务提供端的限流措施&#xff1a; 1.1 使用 &#xff1a;dubbo.protocol.accepts 参数限制服务端同…

面试热点题:回溯算法之组合 组合与组合总和 III

什么是回溯算法&#xff1f; 回溯算法也可以叫回溯搜索算法&#xff0c;回溯是递归的"副产品",回溯的本质是穷举&#xff0c;然后选出我们需要的数据&#xff0c;回溯本身不是特别高效的算法&#xff0c;但我们可以通过"剪枝"来优化它。 理解回溯算法 回溯…

电脑游戏怎么录屏?其实很简单,只需要简单3步

电脑游戏一直是游戏爱好者最热衷的游戏之一。但是&#xff0c;有时候我们想分享我们在游戏中的精彩时刻&#xff0c;或者记录我们的游戏过程以便后续观看和学习。在这种情况下&#xff0c;录屏就成了必不可少的工具。但是&#xff0c;许多人可能不知道电脑游戏怎么录屏。在本文…

逆向分析——壳

你脑海中的壳是什么 壳在自然界是动物的保护壳&#xff0c;软件同样有保护壳&#xff0c;为了防止破解 也许大海给贝壳下的定义是珍珠&#xff0c;也许时间给煤炭下的定义是钻石 ——沙与沫 壳的由来 在DOS时代&#xff0c;壳一般指的是磁盘加密软件中的一段加密程序 后来发展…

APM新添加UAVCAN设备

简介 UAVCAN是一种轻量级协议,旨在通过CAN总线在航空航天和机器人应用中实现可靠通信。要实现通信&#xff0c;最基本需要data_type_ id, signature、数据结构、设备程序初始化。 添加设备数据结构文件(.uavcan格式) 1.在以下路径添加设备数据结构文件&#xff0c;根据设备类…

三体到底是啥?用Python跑一遍就明白了

文章目录拉格朗日方程推导方程组微分方程算法化求解画图动图绘制温馨提示&#xff0c;只想看图的画直接跳到最后一节拉格朗日方程 此前所做的一切三体和太阳系的动画&#xff0c;都是基于牛顿力学的&#xff0c;而且直接对微分进行差分化&#xff0c;从而精度非常感人&#xf…

Web漏洞-CSRF漏洞

CSRF漏洞介绍&#xff1a;CSRF&#xff08;Cross-Site Request Forgery&#xff09;&#xff0c;中文名称&#xff1a;跨站请求伪造&#xff0c;是一种劫持用户在当前已登录的Web应用程序上执行非本意操作一种攻击.原理&#xff1a;攻击者利用目标用户的身份&#xff0c;执行某…

基于Stackelberg博弈的光伏用户群优化定价模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

keras学习之回调函数的使用

回调函数 回调函数是一个对象&#xff08;实现了特定方法的类实例&#xff09;&#xff0c;它在调用fit()时被传入模型&#xff0c;并在训练过程中的不同时间点被模型调用可以访问关于模型状态与模型性能的所有可用数据模型检查点&#xff08;model checkpointing&#xff09;…

【SAP PO】X-DOC:SAP PO 接口配置 REST 服务对接填坑记

X-DOC&#xff1a;SAP PO 接口配置 REST 服务对接填坑记1、背景2、PO SLD配置3、PO https证书导入1、背景 &#xff08;1&#xff09;需求背景&#xff1a; SAP中BOM频繁变更&#xff0c;技术人员在对BOM进行变更后&#xff0c;希望及时通知到相关使用人员 &#xff08;2&…

配天智造自主原创数字工厂:百余名员工人均创收122万

配天智造&#xff08;832223&#xff09;2022年度报告显示&#xff0c;报告期内公司实现营业收入1.3亿元&#xff0c;同比增长52%&#xff0c;归属于挂牌公司股东的净利润3867万元&#xff0c;同比增长28.11%。而这家公司全部在职员工仅有107人&#xff0c;人均创收约为122万。…

计算机科学导论笔记(七)

目录 九、程序设计语言 9.1 演化 9.1.1 机器语言 9.1.2 汇编语言 9.1.3 高级语言 9.2 翻译 9.2.1 编译 9.2.2 解释 9.2.3 翻译过程 9.3 编程模式 9.3.1 面向过程模式 9.3.2 面向对象模式 9.3.3 函数式模式 9.3.4 声明式模式 9.4 共同概念 九、程序设计语言 9.1 …

Spring Cloud Alibaba全家桶(六)——微服务组件Sentinel介绍与使用

前言 本文小新为大家带来 微服务组件Sentinel介绍与使用 相关知识&#xff0c;具体内容包括分布式系统存在的问题&#xff0c;分布式系统问题的解决方案&#xff0c;Sentinel介绍&#xff0c;Sentinel快速开始&#xff08;包括&#xff1a;API实现Sentinel资源保护&#xff0c;…

ABAQUS免费培训 Abaqus成型 焊接 疲劳多工况课程

一、详解Abaqus多工况分析在工程中&#xff0c;多工况的情况是普遍存在的情况&#xff0c;而单工况孤立存在是十分理想状态下的假设。例如我们在进行强度分析时&#xff0c;都是假设其本身是不存在应力的&#xff0c;然后基于这种无初始应力下的计算&#xff0c;使得我们不得不…

aop实现接口访问频率限制

引言 项目开发中我们有时会用到一些第三方付费的接口&#xff0c;这些接口的每次调用都会产生一些费用&#xff0c;有时会有别有用心之人恶意调用我们的接口&#xff0c;造成经济损失&#xff1b;或者有时需要对一些执行时间比较长的的接口进行频率限制&#xff0c;这里我就简…