React快速入门-前端分层(2)

1.Model

1)分层

在这里插入图片描述
上图中,左侧是服务端代码的层次结构,由 Controller、Service、Data Access 三层组成服务端系统:

  • Controller 层``负责与用户直接打交道,渲染页面、提供接口等,侧重于展示型逻辑。
  • Service 层负责处理业务逻辑,供 Controller 层调用。
  • Data Access 层顾名思义,负责与数据源对接,进行纯粹的数据读写,供 Service 层调用

上图的右侧是前端代码的结构,同样需要进行必要的分层:

  • Page 负责与用户直接打交道渲染页面、接受用户的操作输入,侧重于展示型交互性逻辑
  • Model 负责处理业务逻辑为 Page 做数据、状态的读写、变换、暂存等
  • Service 负责与 HTTP 接口对接,进行纯粹的数据读写

2)DVA数据分层管理

dva是基于 redux、redux-saga 和 react-router 的轻量级前端框架。官网:https://dvajs.com/

redux是什么?具体官网中文学习网站链接点击
前端应用的状态管理日益复杂。随着大前端时代的到来,前端愈来愈注重处理逻辑,而不只是专注 UI 层面的改进,而以 React 为代表的前端框架的出现,大大简化了我们编写 UI 界面的复杂度。虽然 React 提供了 State 机制实现状态管理,也有诸如“状态提升”等开发约定,但是这些方案只适用于小型应用,当你的前端应用有多达 10 个以上页面时,如何让应用状态可控、让协作开发高效成为了亟待解决的问题,而 Redux 的出现正是为了解决这些问题而生的!Redux 提出的“数据的唯一真相来源”、单向数据流、“纯函数 Reducers” 大大简化了前端逻辑,使得我们能够以高效、便于协作的方式编写任意复杂的前端应用。
快速学习参考链接

对于dva我们不做过多详细的讲解,我们只要做到能够使用起来就可以了。对于想要全面学习dva框架的同学可自
行研究。
首先,我们先将dva框架引入进来,由于umi对dva进行了整合,所以导入就变得非常简单了。
在config.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;

在这里插入图片描述

mock数据

umi中支持对请求的模拟,由于我们现在没有真正的服务可以返回数据,所以才需要模拟。
在项目根目录下创建mock目录,然后创建MockListData.js文件,并且输入如下内容:

export default {
	'get /ds/list': function (req, res) { //模拟请求返回数据
	res.json({
	data: [1, 2, 3, 4],
		maxNum: 4
	});
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值