本文已参与好文召集令活动,点击查看: 后端、大前端双赛道投稿,2万元奖池等你挑战!
前言
一直想写这个文章很久了,现在终于梳理完了,7月份我打算将React+Dva+UmiJS的写法完整细致地写出来,这次的文章适合Dva、Umi、antd初学者,我会将基础知识点和代码一步一步的较详细地写出来。如果你想直接看代码可以略过前面的这些前提介绍直接看项目和代码讲解噢。
我的项目地址:github.com/Anber-H/rea…
简介
学习本次项目的前提希望你能有React基础,ES6基础,Typescript基础,并阅读过Dva和Umi文档。
本次项目将涉及以下知识点:UmiJS 3、DvaJS、antd、ProTable、ReactHook、TypeScript、DvaJS。
其中主要的知识点有:DvaJs: Subscription、yield、call、Effect、put、dispatch、Reducer、select
ReactHook: useEffect、useState、useRef。
本次项目也就主要围绕这些知识点展开。
基础
下面我想先说明一下react、redux、redux-saga、react-router和umi、dva之间的一个关系,以便于我们能更好的理解之后的知识。
首先我们得要知道:
react:实现UI界面的一个库,没有考虑数据的存储和流向的问题
↓↓↓↓↓↓
redux:专门处理数据的存储和流向的问题
↓↓↓↓↓↓
redux-saga:基于redux的,专门处理异步数据
react-router
文档
(1)、umi文档:umijs.org/zh-CN/docs/…
(2)、dva文档:dvajs.com/
Dva
dva:是一个基于redux和redux-saga的数据流方案。
(1)、也就是说redux和redux-saga是dva的一个基础,dva是一个实现数据流的,也就是实现仓库。
(2)、为了简化开发体验,内置了react-router和fetch。
Umi
umi:Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系。
(1)、umi实际的核心就是路由,也就是react-router
(2)、上述中dva实现了一部分的react-router,umi是把react-router再次进行重新的整合和约定。
关系图
这里我画了一张关系图以便于我们更好地理解:
Dva基本流程
一个项目中有公共数据和私有数据。
在redux中,公共数据就是Redux中Store的概念。
在Dva中提出了一个新的概念:Model。
所以在Dva中我会把Model理解为公共数据,state理解为私有数据。
那么在Dva中页面和仓库是怎么沟通的呢?
首先页面会发起请求,如果是异步数据,需要仓库中专到同步,再返回给页面。
也就是页面发送请求可以是同步也可以是异步,但是回来的时候只有一个口,通过同步返回。
(在dva中我把Reducer理解为同步,Effect理解为异步,当然这是我的理解,只是为了自我方便区分,你也可以有其他的理解)
下面是一张dva的流程图,后期我们写项目的时候可以对照这张流程图完成代码的编写。
从图中我们可以这么通俗理解:
Reducer可以理解为水龙头,水的来源可能不同,但是出水口只有一个,也就是Effect接收不同的接口的数据,然后统一返回给reducer,reducer再统一返回给页面。
搭建基础列表
首先我们来规划一下大概的项目结构:
|-users
|-index.tsx ---------主页面的列表展现
|-model.ts ---------仓库
|-service.ts ---------异步接口的逻辑
|-components ---------文件夹
|-UserModal.tsx
复制代码
这是我们目前想要的一个项目结构(当然后面我们会对这个结构做完整的调整)
那么现在开始进入主题,项目的编写。
完整的目录结构
1、第一步 创建一个空项目react-umi-dva
mkdir react-umi-dva
复制代码
2、第二步 进入到react-umi-dva文件夹并创建项目
yarn create @umijs/umi-app
复制代码
安装完成之后你可以看到react-umi-dva项目中生成了一个目录结构:
├──mock
├──src
├──.editorconfig
├──.gitignore
├──.prettierignore
├──.prettierrc
├──.umirc.ts
├──package.json
├──README.md
├──tsconfig.json
└──typings.d.ts
复制代码
3、第三步 需要在目录结构中添加自己需要的目录:(这里是在src下添加)
├──src
├──pages
├──users
├──components
└──UserModal.tsx
├──index.tsx
├──model.ts
└──service.ts
复制代码
4、第四步 在users/index.tsx页面可以先随便写些什么,然后把项目跑起来看下
export default ()=>{
return <div>洛阳白牡丹</div>
};
复制代码
yarn start
复制代码
注意:这里如果yarn start之后,服务报了Cannot find module ‘umi’这样的一个错,那么你再npm install一下就可以了。
项目运行起来后,你会发现http://10.110.2.70:8000/users 这个页面上什么都没有,那么我们就需要去查看路由。
配置路由
// .umirc.ts中删除下面的这个routes
routes: [
{ path: '/', component: '@/pages/index' },
],
复制代码
为什么是删除这个routes呢?
(1)、.umirc.ts文件中有routes,所以无法进入约定式路由。
(2)、因为umi文档中写道:如果没有 routes 配置,Umi 会进入约定式路由模式。
(3)、而这里刚新建的项目是有这个路由的,所以无法进入约定式路由,是一个手动的路由,那么我们就需要删除这个路由数组。
保存后重新编译,就会看到http://10.110.2.70:8000/users 这个页面有之前你在users/index.tsx中写的东西: 洛阳白牡丹。
list页面
接下来就正式开始写需求了
先将users/index.tsx页面重写
写页面我们都知道有两种方式:类组件和函数组件
这里我用的都是函数组件
// users/index.tsx
// 这里写一个table列表
import React from 'react';
import { Table, Tag, Space } from 'antd';
const index = () => {
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: text => <a>{text}</a>,
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
{
title: 'Tags',
key: 'tags',
dataIndex: 'tags',
render: tags => (
<>
{tags.map(tag => {
let color = tag.length > 5 ? 'geekblue' : 'green';
if (tag === 'loser') {
color = 'volcano';
}
return (
<Tag color={color} key={tag}>
{tag.toUpperCase()}
</Tag>
);
})}
</>
),
},
{
title: 'Action',
key: 'action',
render: (text, record) => (
<Space size="middle">
<a>Invite {record.name}</a>
<a>Delete</a>
</Space>
),
},
];
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer'],
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser'],
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher'],
},
];
return (
<div>
<Table columns={columns} dataSource={data} />
</div>
)
}
export default index
复制代码
ant design中的table列表写进去之后会发现页面的样式有点宽。
所以接下来我们改一下样式:
Umi 中约定 src/global.css 为全局样式,如果存在此文件,会被自动引入到入口文件最前面。
为了方便,所以接下来在src下新建一个global.css文件(全局样式文件),这里面可以写页面的样式,全局使用。
注意:样式写完之后项目需要重新启动才会生效。
.list-table {
width: 850px;
margin: 0 auto;
margin-top: 5%;
border: 1px solid #ccc;
border-radius: 3px;
padding: 10px;
}
复制代码
return (
<div className="list-table">
<Table columns={columns} dataSource={data} />
</div>
)
复制代码
今天先写到这里,还有一些数据的传递,真实数据的获取方法,还有model,弹窗,表单等等的一些写法,在后面的文章中我会继续编写。