前言🐢
看完你能收获🍕
基于umi + dva 的数据处理
- 各层级组件的通信
- 数据mock
的最小最简单最粗糙操作。
本文简单粗暴,就是让你不用看别的,就知道下面这几个东东就能开始整页面。
默认你知道🤔
对react、umi有所了解…基本的函数组件,umi的文件目录能明白是啥,会启动(yarn start)
了解dva😏
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
#特性
- 易学易用,仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用后更是降低为 0 API
- elm 概念,通过 reducers, effects 和 subscriptions 组织 model
- 插件机制,比如 dva-loading 可以自动处理 loading 状态,不用一遍遍地写 showLoading 和 hideLoading
- 支持 HMR,基于 babel-plugin-dva-hmr 实现 components、routes 和 models 的 HMR
图解dva
就是这东东没有新的概念和api,就是基于redux等东东的封装,所以非常好上手。
快速上手🐱🏍
我会想带你配置一下,并且创建几个文件,我再一个个解释,看完你至少能套着我这份最简单最小的demo进行小小的开发。最后也会有一张图解全貌。
umi自带dva,但在配合umi时,要记得在.umirc.js
配置中打开 dva 开关。
还用到了umi自带的,也要打开antd
几个文件
先复制了,然后看结合最后的图解看代码注释,可以自己浅画一下各个组件的联系。
src/pages/dva/index.js
import React from 'react'
//两个子组件
import Search from './search'
import Lists from './lists'
import { connect } from 'dva'
const Dva = props => {
return (
<div>
//将父组件的props用展开运算符传入
<Search {...props} />/
<Lists {...props} />
</div>
)
}
//用connect导出ui组件,并将state中的search作为props传入子组件
export default connect(({ search }) => ({
search,
}))(Dva)
ui组件用connect导出。
connect的作用是将组件和models结合在一起,将models中的state绑定到组件的props中。
并提供一些额外的功能,譬如dispatch
最后返回一个 React 组件,通常称为容器组件,即原始 UI 组件的容器,即在外面包了一层 State。
connect 方法传入的第一个参数是 mapStateToProps 函数,该函数需要返回一个对象,用于建立 State 到 Props 的映射关系。】
src/pages/search.js
import React, { useState } from 'react'
//本质是封装antd-mobile
import { SearchBar } from 'antd-mobile'
//该组件用来做搜索相关的功能
const Search = props => {
const [value, setValue] = useState('')
const handleChange = value => {
setValue(value)
}
const handleSubmit = () => {
//console.log('props', value)
props.dispatch({
//dispatch的选择(命名空间/请求方法标志),以及参数,会去到后面的models文件夹中去找
//type: 'search/getLists',
type: 'search/getListsAsync',
payload: value,
})
}
return (
<div>
<SearchBar
autoFocus
value={value}
onChange={handleChange}
onSubmit={handleSubmit}
/>
</div>
)
}
export default Search
src/pages/lists.js
import React from 'react'
import { List } from 'antd-mobile'
//简简单单展示一下
const Lists = props => {
//console.log(props.search)
//从connect来的search...
const { text, lists } = props.search
return (
<div>
<h1>text:{text}</h1>
<List>
{lists.map((item, i) => (
<List.Item key={i}>{item}</List.Item>
))}
</List>
</div>
)
}
export default Lists
在src文件夹下创建一个新的子文件夹 models —— 用来存放dva相关的代码。
src/models/search.js
//从services(在后面说)中引用调用异步的方法getLists
import { getLists } from '@/services/search'
export default {
//命名空间
namespace: 'search',
//通过connect与ui组件互联的state
state: {
text: 'dva',
lists: [],
},
//方法
//同步
reducers: {
getLists(state, action) {
return {
...state,
lists: Array(10).fill(action.payload),
}
},
},
//异步
effects: {
//call 调用异步函数,puts:事件派发
*getListsAsync({ payload }, { call, put }) {
const res = yield call(getLists, payload)//这里的getLists是引入的异步方法
yield put({
type: 'getLists',
payload: res.lists,
})
},
},
}
再创建一个services 文件夹——放置http相关异步请求
这是nodejs的部分,即这里面的console.log() 是输出在终端中的 因为封装的是express 所以其中的写法与express框架相似。
src/services/search.js
这其中的api自然是数据mock
// export const getLists = value => {
// return fetch(`/api/getLists?value=${value}`).then(res =>
// res.json().catch(err => {
// console.error(err)
// }),
// )
// }
export const getLists = value => {
return fetch(`/api/getListsAsync?value=${value}`).then(res =>
res.json().catch(err => {
console.error(err)
}),
)
}
mock/search.js
注意他不是在src中的,这mock文件夹是umi自带的。
export default {
//value支持函数类型(异步)、json类型(同步)
'GET /api/getLists': {
lists: ['a', 'b', 'c'],
},
'GET /api/getListsAsync': (req, res) => {
console.log(req)
setTimeout(() => {
res.json({
lists: Array(10).fill(req.query.value),
})
}, 1000)
},
}
页面效果
图解
可以看的出来啊,非常的简陋、非常的丑…先凑合着配合理解吧,刚开始用平板写字还是有不习惯啊,以后一定会更好看的。
希望对你有所帮助,有的话点个赞羞辱一下我丑陋的画技吧。
👋