ReactJS入门之Model层

article/2025/8/30 14:28:44

目录

一:分层

二:使用DVA进行数据分层管理

三:在model中请求数据

四:mock数据


一:分层

       上图中,左侧是服务端代码的层次结构,由 Controller Service Data Access 三层组成服务端系统:
  • Controller 层负责与用户直接打交道,渲染页面、提供接口等,侧重于展示型逻辑。
  • Service 层负责处理业务逻辑,供 Controller 层调用。
  • Data Access 层顾名思义,负责与数据源对接,进行纯粹的数据读写,供 Service 层调用。
上图的右侧是前端代码的结构,同样需要进行必要的分层:
  • Page 负责与用户直接打交道:渲染页面、接受用户的操作输入,侧重于展示型交互性逻辑。
  • Model 负责处理业务逻辑,为 Page 做数据、状态的读写、变换、暂存等。
  • Service 负责与 HTTP 接口对接,进行纯粹的数据读写。

二:使用DVA进行数据分层管理

      dva 是基于 redux redux-saga react-router 的轻量级前端框架。官网: https://dvajs.com/
      对于 dva 我们不做过多详细的讲解,我们只要做到能够使用起来就可以了。对于想要全面学习 dva 框架的同学可自 行研究。
     首先,我们先将 dva 框架引入进来,由于 umi dva 进行了整合,所以导入就变得非常简单了。

 confifig.js文件中进行配置:

export default {
plugins: [['umi-plugin-react', {dva: true // 开启dva功能}]
]
};
        接下来,创建 model 文件,在 umi 中,约定在 src/models 文件夹中定义 model ,所以,在该文件夹下创建
ListData.js 文件:

 编写内容:

export default {
namespace: 'list',state: {data: [1, 2, 3],maxNum: 3
}
}
下面对 List.js 进行改造:
import React from 'react';
import { connect } from 'dva';const namespace = 'list';
const mapStateToProps = (state) => {const listData = state[namespace].data;
return {listData
};
};@connect(mapStateToProps)
class List extends React.Component{render(){return (
<div>
<ul>
{
// 遍历值
this.props.listData.map((value,index) => {
return <li key={index}>{value}</li>
})
}
</ul>
<button
onClick={()=>{ //为按钮添加点击事件
// let maxNum = this.state.maxNum + 1;
// let list = [...this.state.dataList, maxNum];
// this.setState({ //更新状态值
// dataList : list,
// maxNum : maxNum
// });
}}>
添加</button>
</div>
);
}
}export default List;
测试:

 可以看到,效果是一样的。

流程说明:
1. umi 框架启动,会自动读取 models 目录下 model 文件,即 ListData.js 中的数据
2. @connect 修饰符的第一个参数,接收一个方法,该方法必须返回 {} ,将接收到 model 数据
3. 在全局的数据中,会有很多,所以需要通过 namespace 进行区分,所以通过 state[namespace] 进行获取数据
4. 拿到 model 数据中的 data ,也就是 [1, 2, 3] 数据,进行包裹 {} 后返回
5. 返回的数据,将被封装到 this.props 中,所以通过 this.props.listData 即可获取到 model 中的数据
刚刚只是将数据展现出来,如果点击按钮,需要修改 state 的值,怎么操作呢?
首先,在 model 中新增 reducers 方法,用于更新 state 中的数据:
export default {
namespace: 'list',
state: {
data: [1, 2, 3],
maxNum: 3
},
reducers : {
addNewData(state){ //state是更新前的对象
let maxNum = state.maxNum + 1;
let list = [...state.data, maxNum];
return { // 返回更新后的state对象
data : list,
maxNum : maxNum
}
}
}
}
接下来修改 List.js 新增点击事件:
import React from 'react';
import { connect } from 'dva';
const namespace = 'list';
const mapStateToProps = (state) => {
const listData = state[namespace].data;
const maxNum = state[namespace].maxNum;
return {
listData, maxNum
};
};
const mapDispatchToProps = (dispatch) => { // 定义方法,dispatch是内置函数
return { //返回的这个对象将绑定到this.props对象中
addNewData : () =>{ // 定义方法
dispatch({ // 通过调用dispatch()方法,调用model中reducers的方法
type: namespace + "/addNewData" // 指定方法,格式:namespace/方法名
});
}
}
}
@connect(mapStateToProps, mapDispatchToProps) //mapDispatchToProps:函数,将方法映射到
props中
class List extends React.Component{
render(){
return (
<div>
<ul>
{
// 遍历值
this.props.listData.map((value,index) => {
return <li key={index}>{value}</li>
})
}
</ul>
<button
onClick={()=>{this.props.addNewData()}}>
添加
</button>
</div>
);
}
}
export default List;
测试:

测试结果,和之前实现效果一样。
流程梳理如下:

 

三:model中请求数据

        前面我的数据是写死在 model 中的,实际开发中,更多的是需要异步加载数据,那么在 model 中如何异步加载数据 呢?
       首先,创建 src 下创建 util 目录,并且创建 request.js 文件,输入如下内容:(用于异步请求数据)
// import fetch from 'dva/fetch';function checkStatus(response) {if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default async function request(url, options) {
const response = await fetch(url, options);
checkStatus(response);
return await response.json();
}
然后,在 model 中新增请求方法:
import request from '../util/request';export default {
namespace: 'list',
state: {
data: [],
maxNum: 0
},reducers: {
addNewData(state, result) { //result就是拿到的结果数据
if(result.data){ //判断result中的data是否存在,如果存在,说明是初始化数据,直接返回
return result.data;
}let maxNum = state.maxNum + 1;
let list = [...state.data, maxNum];
return { //更新状态值
data: list,
maxNum: maxNum
}
}
},
effects: { //新增effects配置,用于异步加载数据
*initData(params, sagaEffects) { //定义异步方法
const {call, put} = sagaEffects; //获取到call、put方法
const url = "/ds/list"; // 定义请求的url
let data = yield call(request, url); //执行请求
yield put({ // 调用reducers中的方法
type : "addNewData", //指定方法名
data : data //传递ajax回来的数据
});
}
}
}
改造页面逻辑:
import React from 'react';
import { connect } from 'dva';const namespace = 'list';const mapStateToProps = (state) => {
const listData = state[namespace].data;
const maxNum = state[namespace].maxNum;
return {
listData, maxNum
};
};const mapDispatchToProps = (dispatch) => {return {
addNewData : () =>{dispatch({
type: namespace + "/addNewData"
});
},initData : () => { //新增初始化方法的定义
dispatch({
type: namespace + "/initData"
});
}
}
}
@connect(mapStateToProps, mapDispatchToProps)
class List extends React.Component{
componentDidMount(){
this.props.initData(); //组件加载完后进行初始化操作
}
render(){
return (
<div>
<ul>
{
// 遍历值
this.props.listData.map((value,index) => {
return <li key={index}>{value}</li>
})
}
</ul>
<button
onClick={()=>{this.props.addNewData()}}>
添加
</button>
</div>
);
}
}export default List;
测试:
测试结果,发现会报错,原因是返回的数据不是 json 导致,解析出错。
查看下请求:

 可以看到,返回的是html代码,所以会导致出错。

完整的List.js页面代码:

import React from 'react';
import { connect } from 'dva';const namespace = "list";// 说明:第一个回调函数,作用:将page层和model层进行链接,返回modle中的数据
// 并且,将返回的数据,绑定到this.props// 接收第二个函数,这个函数的作用:将定义的函数绑定到this.props中,调用model层中定义的函数
@connect((state) => {return {dataList : state[namespace].data,maxNum : state[namespace].maxNum}
}, (dispatch) => { // dispatch的作用:可以调用model层定义的函数return { // 将返回的函数,绑定到this.props中add : function () {dispatch({ //通过dispatch调用modle中定义的函数,通过type属性,指定函数命名,格式:namespace/函数名type : namespace + "/addNewData"});},init : () => {dispatch({ //通过dispatch调用modle中定义的函数,通过type属性,指定函数命名,格式:namespace/函数名type : namespace + "/initData"});}}
})
class  List extends React.Component{componentDidMount(){//初始化的操作this.props.init();}render(){return (<div><ul>{this.props.dataList.map((value,index)=>{return <li key={index}>{value}</li>})}</ul><button onClick={() => {this.props.add();}}>点我</button></div>);}}export default List;

完整的ListData.js页面代码:

import request from '../util/request';export default {namespace: 'list',state: {data: [],maxNum: 1},reducers : { // 定义的一些函数addNewData : function (state, result) { // state:指的是更新之前的状态数据, result: 请求到的数据if(result.data){ //如果state中存在data数据,直接返回,在做初始化的操作return result.data;}let maxNum = state.maxNum + 1;let newArr = [...state.data, maxNum];return {data : newArr,maxNum : maxNum}//通过return 返回更新后的数据}},effects: { //新增effects配置,用于异步加载数据*initData(params, sagaEffects) { //定义异步方法const {call, put} = sagaEffects; //获取到call、put方法const url = "/ds/list"; // 定义请求的urllet data = yield call(request, url); //执行请求yield put({ // 调用reducers中的方法type : "addNewData", //指定方法名data : data //传递ajax回来的数据});}}
}

完整的request.js页面代码:

// import fetch from 'dva/fetch';function checkStatus(response) {if (response.status >= 200 && response.status < 300) {return response;}const error = new Error(response.statusText);error.response = response;throw error;
}/*** Requests a URL, returning a promise.** @param  {string} url       The URL we want to request* @param  {object} [options] The options we want to pass to "fetch"* @return {object}           An object containing either "data" or "err"*/
export default async function request(url, options) {const response = await fetch(url, options);checkStatus(response);return await response.json();
}

四:mock数据

umi 中支持对请求的模拟,由于我们现在没有真正的服务可以返回数据,所以才需要模拟。
在项目根目录下创建 mock 目录,然后创建 MockListData.js 文件,并且输入如下内容:
export default {
'get /ds/list': function (req, res) { //模拟请求返回数据
res.json({
data: [1, 2, 3, 4],
maxNum: 4
});
}
}
进行测试:
发现,可以正常返回数据了。
页面效果也正常了 :

 


http://chatgpt.dhexx.cn/article/hRBAecGE.shtml

相关文章

初识Jstorm 多个bolt应用

最近接到任务说要使用jstorm处理业务&#xff0c;之前没接触过&#xff0c;只能硬着头皮来&#xff0c;接下来谈谈我这两天的收获 1&#xff0c;怎么了解jstorm&#xff0c;这个答案没什么固定的&#xff0c;但是我个人比较喜欢去看官方的文档&#xff0c;如果官方的文档实在找…

大数据(十五) - JStorm

JStorm 是一个分布式实时计算引擎&#xff0c;是淘宝开源的 随着Storm 的规模越来越大&#xff0c;发现原有的很多Storm设计&#xff0c;只能适合小集群中运行&#xff0c;当集群规模超过100台时&#xff0c;均会出现一些或这或那的问题。JStorm 比Storm更稳定&#xff0c;更强…

初识JavaScript---(1)

初识JavaScript———&#xff08;1&#xff09;&#xff01;&#xff01;&#xff01; 一、初识JavaScript 1.什么是JavaScript&#xff1f; JavaScript是运行在浏览器上的脚本语言&#xff0c;简称JS。JavaScript程序不需要我们程序员手动编译&#xff0c;编写完源代码之后…

【JavaScript高级进阶】构造函数和原型,学会prototype

目录 前言 1.构造函数和原型 1.1使用prototype解决内存浪费的问题 1.2constructor构造函数构造器构造函数 2.原型链 2.1js中成员查找规则 2.2原型对象this指向 2.3扩展内置对象 3.call作用 4.继承 4.1利用原型对象继承 写在最后 前言 哈喽哈喽大家好&#xff0c;因为…

Jstorm 基本概念

本质 基于消息的流水线处理模型是一套类似MapReduce一样的编程模型内核是一套调度系统 适合的业务 高并发的计算任务数据流之间相互无依赖 编程模型 Topology&#xff1a;即一个数据流的拓扑结构&#xff0c;包含多个Spout和BoltSpout&#xff1a;从外部获取数据&#xff…

JStorm和Storm比较

1、What——JStorm是什么&#xff1f;  概述&#xff1a; JStorm 是一个分布式实时计算引擎&#xff0c;类似Hadoop MapReduce的系统&#xff0c; 用户按照规定的编程规范实现一个任务&#xff0c;然后将这个任务递交给JStorm系统&#xff0c;Jstorm将这个任务跑起来&#xf…

JStorm Storm 上手demo

折线之间的内容整理自&#xff1a; http://blog.csdn.net/suifeng3051/article/details/38369689 -------------------------------------------------------------------------------------------------------------------------------------------- 在全面介绍Storm之前&…

PyTorch从零开始实现Transformer

文章目录 自注意力Transformer块编码器解码器块解码器整个Transformer参考来源全部代码&#xff08;可直接运行&#xff09; 自注意力 计算公式 代码实现 class SelfAttention(nn.Module):def __init__(self, embed_size, heads):super(SelfAttention, self).__init__()self.e…

jstorm storm 入门demo

jstorm和storm比较 jstorm 是阿里巴巴开源的基于storm采用Java重写的一套分布式实时流计算框架&#xff0c;使用简单&#xff0c;特点如下&#xff1a; 1&#xff0c;开发非常迅速: 接口简单&#xff0c;容易上手&#xff0c;只要遵守Topology&#xff0c;Spout&#xff0c;Bo…

JStorm介绍

一、简介 JStorm是一个分布式实时计算引擎。JStorm是一个类似于Hadoop MapReduce的系统&#xff0c;用户按照指定的接口实现一个任务&#xff0c;然后将这个任务交给JStorm系统&#xff0c;JStorm将这个任务跑起来&#xff0c;并按7*24小时运行。如果中间一个worker发生了意外…

马氏距离实例详解

介绍 马氏距离是由印度统计学家马哈拉诺比斯&#xff08;P. C. Mahalanobis&#xff09;提出的&#xff0c;表示数据的协方差距离。它是一种有效的计算两个未知样本集的相似度的方法。与欧氏距离不同的是它考虑到各种特性之间的联系&#xff08;例如&#xff1a;一条关于身高的…

距离度量:闵氏、欧式、马氏、余弦、汉明等

目录 1. 闵氏距离&#xff08;Minkowski Distance&#xff09; 2. 欧式距离&#xff08;Euclidean Distance&#xff09; 3. 标准化欧式距离&#xff08;Standardized Euclidean distance&#xff09; 4. 马氏距离&#xff08;Mahalanobis Distance&#xff09; 5. 余弦距…

马氏距离(Mahalanobis Distance)推导及几何意义

看了一些博客对马氏距离的解释&#xff0c;似乎没有讲到本质的地方&#xff0c;本文从欧氏距离存在的问题开始入手&#xff0c;一步步推导出马氏距离&#xff0c;并得出结论&#xff1a;原始空间中的马氏距离等于坐标旋转变换及缩放后的空间中的欧氏距离。 假设数据集 X ∈ R N…

直观理解--马氏距离

首先我们很了解欧氏距离了&#xff0c;就是用来计算欧式空间&#xff08;就是我们常见的坐标系&#xff09;中两个点的距离的。 比如点 x ( x 1 , … , x n ) x (x_1,…,x_n) x(x1​,…,xn​) 和 y ( y 1 , … , y n ) y (y_1,…,y_n) y(y1​,…,yn​) 的欧氏距离为&…

Mahalanobis距离(马氏距离)的“哲学”解释

讲解教授&#xff1a;赵辉 (FROM : UESTC) 课程&#xff1a;《模式识别》 整理&#xff1a;PO主 基础知识&#xff1a; 假设空间中两点x&#xff0c;y&#xff0c;定义&#xff1a; 欧几里得距离&#xff0c; Mahalanobis距离&#xff0c; 不难发现&#xff0c;如果去掉…

六大距离:欧式距离、街道距离、马氏距离等

文章目录 1 简 介2 距离特征2.1 Euclidean距离2.2 Cosine距离2.3 manhattan距离2.4 chebyshev距离2.5 minkowski距离2.6 mahalanobis距离 3 代 码实现 1 简 介 数值向量是数据建模问题中最为常见的一类特征&#xff0c;例如&#xff1a; 在一些涉及图片&#xff0c;文本信息等…

马氏距离例题详解(全网最详细)

马氏距离例题详解 定义 马哈拉诺比斯距离是由印度统计学家马哈拉诺比斯 (英语)提出的&#xff0c;表示数据的协方差距离。它是一种有效的计算两个未知样本集的相似度的方法。与欧氏距离不同的是它考虑到各种特性之间的联系&#xff08;例如&#xff1a;一条关于身高的信息会带…

浅谈马氏距离【Mahalonobis Distance】

浅谈马氏距离【Mahalonobis Distance】 1. Introduction2. 欧式距离对于多元数据会存在一些什么问题&#xff1f;3 .什么是马氏距离4.马氏距离背后的数学和intuition5. 利用python来计算马氏距离6. Case1: 使用马氏距离进行多元异常值检测7. Case 2: 对分类问题应用马氏距离8. …

距离度量之马氏距离

马氏距离 用来度量一个样本点&#xff30;与数据分布为&#xff24;的集合的距离。 假设样本点为&#xff1a; 数据集分布的均值为&#xff1a; 协方差矩阵为&#xff33;。 则这个样本点&#xff30;与数据集合的马氏距离为&#xff1a; 马氏距离也可以衡量两个来自同一…

马氏距离(Mahalanobis Distance)介绍与实例

本文介绍马氏距离&#xff08;Mahalanobis Distance&#xff09;&#xff0c;通过本文&#xff0c;你将了解到马氏距离的含义、马氏距离与欧式距离的比较以及一个通过马氏距离进行异常检测的例子&#xff08;基于Python的sklearn包&#xff09;。 目的 计算两个样本间的距离时…