之前色老师给我们线上开过一个小会,会议内容是带领我们浏览一下多译的代码,以及umi框架的架构。
这几天我完成了自己MiniProject的前端部分,在这里记录一下这一套框架的简单使用情况。
1、路由的配置
在config目录下,有一个router.ts,其中定义了路由信息。
我照猫画虎,在已有的页面后面增加了changelog界面。
关于这部分,我其实并不能理解其路由的结构,尤其是其嵌套的形式。TODO: 以后有时间好好读一下umi的文档。(最近确实比较忙,还是先把项目做出来再说吧)
2、源代码的结构
源代码的目录下主要由几部分构成
1 2 3 4 5
| components ------一些组件 layouts models ------model的定义,或者说Redux的定义 pages ------页面 services ------提供给model的一些方法,诸如http请求等
|
说来惭愧,layouts部分色老师也讲过,但是我好巧不巧当时走神了。后来看了一下也没太能看懂…..
TODO: 抽空了解一下 layouts的作用
3、model 结构
model由一个 connect.d.ts
和 若干个ts文件组成。其中前者像是model的入口文件,其他ts文件则分别定义了若干个store
这一点在之前学习Redux的时候,印象中阮一峰老师有提到过大的项目中store通常会分开管理,然后Redux提供了将它们合并的方法。
我在model中新建了 changelog.ts
文件,用来定义更新日志的store,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| import { DvaModel, Effect } from '@/models/connect'; import { getChangelog, uploadChangelog } from '@/services/changelog';
export interface LogItem { url: { win: string; mac: string; }; version: string; createdAt: Date; updatedAt: Date; description: string; }
export interface ChangelogModelState { data: LogItem[]; IsSuccess: boolean; messege: String; }
export interface ChangelogModel extends DvaModel<ChangelogModelState> {}
const Model: ChangelogModel = { state: { data: [], IsSuccess: false, messege: '', }, reducers: { save(state, { payload }) { return { ...state, ...payload, }; }, }, effects: { *fetchData(_, { call, put }) { const res = yield call(getChangelog); const { success, data } = res; if (success) { yield put({ type: 'save', payload: { data }, }); } }, *uploadData({ payload }, { call, put }) { let data = payload; try { const res = yield call(uploadChangelog, data); if (res && res.success) { yield put({ type: 'save', payload: { IsSuccess: true }, }); } } catch (e) { const { response } = e; const { status } = response; if (status === 409) { yield put({ type: 'save', payload: { messege: '版本已存在' }, }); } if (status === 401) { yield put({ type: 'save', payload: { messege: '没有权限提交' }, }); } } }, }, }; export default Model;
|
首先需要定义store中state的接口,如代码中的 ChangelogModelState
,这里的命名我参照了色老师其他store的命名,以此来规范代码中的变量名。
接着定义了model的接口,ChangelogModel
,这个接口继承了 DvaModel
,并且将自己定义的state的类型作为泛型实例化。
最后利用继承来的类型来定义Model,并且完成state的初始化。
reducers 和 effects 共同定义了action的类型,其中effects定义了具有副作用的action。包括那些需要进行网络请求的action。 reduces则是一些直接更新state的纯函数。
在effects中,我们可以传递call put 方法,其中call方法可以用来调用request,put则可以通过action来执行reducer中的方法。
一个值得注意的点: 在reducer和effects中参数中的payload要用解构赋值, fetchData({payload},_)
这样payload才是我们调用dispatch时传入的payload。(最开始没有用解构赋值,然后发现获取不到数据,查bug查了好久,哭)
接着在connect.d.ts中添加changelog的入口。(这部分代码由于涉及色老师写的,因此不方便贴出来)
TODO: 抽空去看一下 .d.ts
这个后缀的文件名和 .ts
之间的区别
4、页面(组件)
4.1 组件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| @connect(({ changelog }: ConnectState) => ({ data: changelog.data, })) export default class Changelog extends Component<DispatchProps> { componentDidMount(): void { this.props.dispatch({ type: 'changelog/fetchData' }); } render() { return ( <Fragment> <Row> <Col span="1.5"></Col> <Col span="22.5"> <h1>更新日志</h1> </Col> </Row> <Timeline>{this.myTimelineItem()}</Timeline> </Fragment> ); } myTimelineItem() { return this.props.data.map((item, index) => { return ( <Timeline.Item> <Row> <Col span="1"></Col> <Col span="23"> <Typography> <Title level={3}>{item.version}</Title> {this.myDate(item.createdAt)} <Paragraph> <ul>{this.myLi(item.description)}</ul> </Paragraph> </Typography> </Col> </Row> </Timeline.Item> ); }); } myLi(description: String) { let arr = description.split('\n'); let sta = []; for (let i = 0; i < arr.length; i++) if (arr[i] === '') sta.push(i); for (let i = 0; i < sta.length; i++) arr.splice(sta[i], 1); return arr.map((item, index) => <li>{item}</li>); } myDate(createdAt) { if (createdAt) { let arr = createdAt.split('T'); return <Tag>{arr[0]}</Tag>; } } }
|
首先要先 connect,这里是Dva的语法
接着就是组件类的定义。didMount 生命周期中发送 action: fetchData,这是个异步的action,会发送网络请求,然后更新state。根据上面我们model中的定义,会在请求结束后拿到数据后更新changelog model中的data数据。同时View也会相应的进行响应。
render函数中是对于界面的描述。
4.2 Ant Design
色老师给我推荐了一个组件库 Ant Design。 我去官网找了个时间轴组件,按照组件介绍的代码直接使用,发现其使用方法非常简单。
使用data数组的 map 方法来返回 Timeline的item。 这一点参考了之前的React实践视频
5、感悟
在别人项目的基础上写代码真是一件过于easy的事情(不是。
正经:在别人项目的基础上进行实践来学习新知识真是一件很爽的事情。我们只需要关注自己需要的部分,想办法解决手头很明确的需求,在此过程中,或者查文档,或者问学长,很快解决之后能够立刻学到很多。在这次Miniproject的过程中,我从对于React一无所知,到尝试使用了 Umi、Dva等等等框架。尽管我对于那些框架其实并没有很了解,但是我相信在之后的实践过程中总有一天会把这些TODO给逐渐消除。