Dva 初体验

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

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

简单来说 Dva 类似于 Redux 之于 React,二者可以更好的搭配,通过 Dva 管理状态,可以分离 JSX 组件中的大量状态控制,使代码更加清爽易读。

比起 redux-saga,减少了大量的文件分离,只用一个 model 文件就可以定义定义一个状态中心。


初始化


现在 Dva 已经集成到了 Umi(本文使用 Umi4) 内部,需要在 Umi 的配置文件中打开 Dva 的选项(直接添加配置是会报错的,需要通过微生成器添加,往下看

umi: {}
复制代码

使用 Umi 脚手架创建项目,以下三种方式任选其一,推荐使用 pnpm,选择标准项目即可。

$ pnpm dlx create-umi@latest
$ npx create-umi@latest
$ yarn create umi
复制代码

创建项目之后使用 umi 的微生成器来初始化 dva

$ pnpm umi g dva
// 如果是本地全局安装的 umi
$ umi g dva
复制代码

然后 .umirc.ts 配置文件中会自动生成 dva 的相关配置

export default defineConfig({
  npmClient: "pnpm",
  dva: {},
  plugins: ["@umijs/plugins/dist/dva"],
});
复制代码

并且生成 model 文件

1682565624(1).png

现在 dva 已经初始化完成了,我们继续来看 dva 的使用


工作流


dva 的工作流如下:

1682565601(1).png

数据统一在 src/models 中的 model 管理,组件内尽可能的不去维护数据,而是通过 connect 去关联 model 中的数据。页面有操作的时候则触发一个 action 去请求后端接口以及修改 model 中的数据,将业务逻辑分离到一个环形的闭环中,使得数据在其中单向流动。让应用更好维护。这样的思想最初来源于 Facebook 的 flux。接下来我们来具体看看如何在 Umi 中实现这样的逻辑。

models

Umi 会默认将 src/models 下的 model 定义自动挂载,你只需要在 model 文件夹中新建文件即可新增一个 model 用来管理组件状态。

需要注意的是 model 的 namespace 是全局的,你仍然需要保证你的 namesapce 唯一(默认是文件名)

一个 model 中可以定义如下几个部分:

  • namespace : model 的命名空间,唯一标识一个 model,如果与文件名相同可以省略不写
  • state : model 中的数据
  • effects : 异步 action,用来发送异步请求
  • reducers : 同步 action,用来修改 state

connect

connect 用于将model 和组件关联在一起,会将 state 和dispatch 添加到组件的 props 中。

如果你熟悉 redux,这个 connect 就是 react-redux 的 connect 。

我们使用初始化时生成的 model 来做示例,注意要将示例的 add action添加返回值,否则调用之后会报错。

import { connect } from "umi"
export function CountPage(props: any) {
  const { loading, dispatch, count: {num} } = props
  const addHandler = () => {
    dispatch({
      type: 'count/addAsync'
    })
  }
  return <div>
    {num}
    <button onClick={addHandler}>+</button>
  </div>
}
export default connect(
  ({ loading, count }: any) => ({ loading, count })
)(CountPage)
复制代码

1682565653(1).png

框架会默认添加一个命名空间为 loading 的 model,该 model 包含 effects 异步加载 loading 的相关信息,它的 state 格式如下:

{
  global: Boolean, // 是否真正有异步请求发送中
  models: {
    [modelnamespace]: Boolean, // 具体每个 model 的加载情况
  },
  effects: {
    [modelnamespace/effectname]: Boolean, // 具体每个 effect 的加载情况
  },
}
复制代码

函数组件的使用方式大致如上所述,类组件的使用方式更加简洁,使用装饰器语法可以将 dva 进行注入。

@connect(({ count }) => ({ count }))
class CountPage extends React.Component {
  constructor(props: any) {
    super(props);
  }
  addHandler() {
    this.props.dispatch({ 
      type: 'count/addAsync'
    })
  }
  render() {
    return (
      <div>
        {this.props.count.num}
        <button onClick={() => this.props.dispatch({
          type: 'count/addAsync'
        })}>+</button>
      </div>
    )
  }
}
export default CountPage
复制代码

但是目前对 TS 的语法检查支持不是很友好,会有一些爆红,此外,model 中 action 的返回值一定要是一个新的值,也就是说如果 state 是一个对象类型不能直接返回,引用地址相同 dva 会认为没有改变,从而导致页面不会更新


定义 model 核心


namespace

namespace是 model 的唯一标识,通过 namespace 来操作不同的 model,namespace 必须唯一,否则会导致数据混乱

state

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

定义的 state就是 model 的初始数据,可以在初始化时拿到。

state: {
  num: 0,
  time: 1000,
},
复制代码

reducer

reducer 是一个函数,用来处理修改数据的逻辑(同步,不能请求后端)。接受 state 和 action,返回老的或新的 state 。即:(state, action) => state

在 model 中,reducer 用于修改数据,在异步请求之后,或者任意 action 触发都可以调用 reducer 来更新 state

reducers: {
  add(state, { payload: todo }) {
    return state.concat(todo);
  },
  remove(state, { payload: id }) {
    return state.filter(todo => todo.id !== id);
  },
  update(state, { payload: updatedTodo }) {
    return state.map(todo => {
      if (todo.id === updatedTodo.id) {
        return { ...todo, ...updatedTodo };
      } else {
        return todo;
      }
    });
  },
},
复制代码

effect

effect 可以进行异步操作,基于生成器函数来完成一步流程,这一点也是继承自 redux-saga

effects: {
  *addAsync(_action: any, { put, call, select }: any) {
    const time = yield select(state => state.time)
    yield call(delay, time);
    yield put({ type: 'add' });
  },
},
复制代码

effect 中定义的异步 action接收两个参数,第一个参数是 Action,通常用于接收 payload;第二个参数是 dva 提供的函数 select(从 state 中获取数据)、put(触发 action)、call(执行异步函数)

dispatch

dispatch 用于model 外部触发 model 内定义的 action(effect和 reducer 都属于 action),在外部触发时需要添加 namespace,如 model 中定义了名为 getData 的 effect,那么在 model 外部触发时需要使用如下方式

dispatch({
  type: 'count/getData',
  payload: {
    page: 1,
    size: 10
  }
})


相关文章
|
缓存 资源调度 内存技术
yarn报错文件名、目录名或卷标语法不正确
yarn报错文件名、目录名或卷标语法不正确
780 0
|
小程序 开发工具 git
【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)
【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)
|
JSON 小程序 前端开发
微信小程序框架(五)-全面详解(学习总结---从入门到深化)
微信小程序框架(五)-全面详解(学习总结---从入门到深化)
641 0
|
3月前
|
运维 监控 安全
单点登录SSO最佳实践:加强安全性与简化访问流程
单点登录(SSO)技术凭借“一套凭证畅行多个应用”的核心特性,极大简化了用户的登录操作。不过,SSO 在提升便捷性的同时,也将关键系统的访问入口集中化,因此必须落实一系列最佳实践,才能切实守护用户凭证与敏感数据的安全。
137 0
|
4月前
|
JavaScript 算法 数据安全/隐私保护
解决Node.js错误:“error:0308010C:digital envelope routines::unsupported”
在应用上述解决方案前,请确保你的Node.js应用程序的所有依赖都是最新的,这可以通过运行 npm update来实现。同时,始终备份你的工作,以防需要回滚所做的任何更改。通过这些步骤,多数情况下应该能够解决"error:0308010C:digital envelope routines::unsupported"错误问题。这些解决方案能确保应用程序可以顺利运行,同时也为今后可能的OpenSSL库更新做好了准备。
636 16
|
8月前
|
Web App开发 安全 算法
什么是一次性密码(OTP)
一次性密码(OTP)是一种动态生成的临时身份验证代码,仅能使用一次且有效期短,通常为30-60秒。它作为多因素认证的重要组成部分,通过设备或应用生成唯一代码,提升账户安全性,减少密码重用和拦截风险,广泛应用于金融、企业安全、电商等领域。
3622 87
|
11月前
|
自然语言处理 安全 数据挖掘
Hologres+函数计算+Qwen3,对接MCP构建企业级数据分析 Agent
本文介绍了通过阿里云Hologres、函数计算FC和通义千问Qwen3构建企业级数据分析Agent的解决方案。大模型在数据分析中潜力巨大,但面临实时数据接入与跨系统整合等挑战。MCP(模型上下文协议)提供标准化接口,实现AI模型与外部资源解耦。方案利用SSE模式连接,具备高实时性、良好解耦性和轻量级特性。Hologres作为高性能实时数仓,支持多源数据毫秒级接入与分析;函数计算FC以Serverless模式部署,弹性扩缩降低成本;Qwen3则具备强大的推理与多语言能力。用户可通过ModelScope的MCP Playground快速体验,结合TPC-H样例数据完成复杂查询任务。
|
7月前
|
存储 搜索推荐 安全
Java 大视界 --Java 大数据在智能教育学习效果评估与教学质量改进中的应用(209)
本文探讨了 Java 大数据在智能教育中的创新应用,涵盖学习效果评估、教学质量改进及个性化教学方案定制等内容,结合实战案例与代码解析,展现技术如何赋能教育智能化转型。
|
缓存 小程序 API
微信小程序页面导航与路由:实现多页面跳转与数据传递
本文深入探讨微信小程序的页面导航与路由机制,介绍多种页面跳转方式如`wx.navigateTo`、`wx.redirectTo`、`wx.switchTab`等,并讲解通过URL、全局变量和事件传递数据的方法。结合案例实现多页面跳转与数据传递,帮助开发者掌握这一重要技能。
|
弹性计算 Java 网络协议
……企业搭建门户网站需要考虑的事情就很多了?
企业门户网站不同于普通网站,它不仅是品牌形象的展示,还集品牌宣传、销售、服务、互动、数据营销等多功能于一体。企业搭建门户需考虑多地访客的访问速度、定制开发及高昂成本。为解决这些问题,中小企业转向云服务,如阿里云提供的解决方案,利用云效流水线自动化构建和发布,通过ROS快速创建ECS,结合DNS解析和CDN加速,实现高效低成本的部署。此方案简化了上线的流程,但完整的开发还包括设计、开发、测试等环节在本解决方案中没有体现。
724 1
……企业搭建门户网站需要考虑的事情就很多了?

热门文章

最新文章