蚂蚁金服开源的企业级React框架,并不是UI框架
1.特性
- 开箱即用,内置 react、react-router
...
- 类似 next.js 且功能完备的路由约定,同时也支持手动配置路由的方式;
- 完善的插件体系,高性能,通过插件支持PWA、以路由为单元的code splitting等等;
- 支持静态页面导出,适配各种环境,如中台业务、无线业务、egg、支付宝钱包
- 开发启动快,支持一键开启dll
- 一键兼容IE9、基于 umi-plugin-polyfills
- 支持TypeScript
- 与 dva 数据流的深入融合,支持duck directory、model的自动加载、code splitting等等
![](https://img2020.cnblogs.com/blog/1190299/202010/1190299-20201029143024668-901675592.png)
1. State:一个对象,保存整个应用状态; 2. View:React组件构成的视图层; 3. Action:一个对象,描述事件 4. connect():绑定```State```到```View``` 5. dispatch():发送```Action```到```State```
3.dva 与 umi 的约定
1.src 源码:pages(页面)、components(组件)、layout(布局)、model(数据模型)
2.config 配置
3.mock 数据模拟
4.test 测试
4.全局安装脚手架: npm i umi -g快速上手
"scripts": { "start": "umi dev", "build": "umi build" }
cd src umi g page index // index.js和index.css umi g page about // bout.js和about.css
5、运行项目:npm start,自动编译生成页面配置 /src/pages/.umi 目录
,且项目是热部署;
http://localhost:8000/ --> index.js http://localhost:8000/about --> about.js
6、引入公共 css (根据个人需求,可要可不要)
在 src 目录下新建 global.css/.less
7、创建全局布局 layouts,如公共头部、尾部 (根据个人需求,可要可不要)
src/layouts 目录中的 index.js 将成为项目的定级布局页面,使用 {props.children} 显示 src/pages 目录中的组件。
在 src 目录下,创建文件夹 layouts
在 layouts 目录下,创建 index.js、index.less
import styles from './index.css'; import {Layout} from 'antd'; const {Header, Content, Footer} = Layout; export default (props) => { return ( <Layout> <Header> <div style={{color: 'white'}}>王者资料库</div> </Header> <Content style={{padding: '0 50px'}}> {props.children} </Content> <Footer style={{textAlign: 'center'}}>footer</Footer> </Layout> ) }
约定式路由嵌套 (Link、history)
1、当出现 _layout.js 页面时默认为父组件页面,通过 {props.children} 显示子组件内容;
2、嵌套路由:/users,创建 pages/users 目录
umi g page users/_layout // pages/users/_layout.js、_layout.css
1.pages/users/_layout.js
import React from 'react'; import styles from './_layout.css'; export default (props) => { return ( <div className={styles.normal}> <h1 className={styles.title}>Page users/_layout</h1> <div>{props.children}</div> </div> ); }
2.为 _layout.js 创建子组件,users 的首页 index.js
umi g page users/index // pages/users/index.js、index.css
3.访问嵌套路由:http://localhost:8000/users
3、约定 []
包裹的文件或文件夹为动态路由、users/[name].js 对应路由为 /users/:name
- 在 users 目录中,再创建 [name].js、[name].css
- 访问 [name].js:http://localhost:8000/users/xxx
4、跳转路由 (Link,history)
1.users/index.js
import React from 'react'; import styles from './index.css'; import {Link} from 'umi'; export default () => { const userList = [ {id: 1, name: 'Tim'}, {id: 2, name: 'Jarry'} ] return ( <div> <ul> { userList.map(item => ( <li key={item.id}> <Link to={`/users/${item.name}`}>{item.name}</Link> </li> )) } </ul> </div> ); }
2.users/[name].js
import React from 'react'; import styles from './[name].css'; import {history} from 'umi'; export default (props) => { return ( <div> <h1 className={styles.title}>Page users/[name]</h1> <h2>{props.match.params.name}</h2> <button onClick={()=>props.history.goBack()}>返回</button> </div> ); }
配置式路由
1、配置式路由一旦创建,约定式路由自动失效,umi不会再自动创建路由;
2、在项目根目录下创建 config 目录,并创建 config.js文件;
// 没有设置全局 layouts 布局 export default { // 路由配置:路径相对于 src/pages routes: [ {path: '/', component: './index'}, {path: '/about', component: './about'}, { path: '/users', component: './users/_layout', routes: [ {path: '/users', component: './users/index'}, {path: '/users/:name', component: './users/[name]'}, ] }, {component: './notfound'} // 404页面,上面的所有路由都没有匹配时,则匹配404页面 ], }
// 设置了全局 layouts 布局 export default { // 路由配置:路径相对于 src/pages routes: [ { path: '/', component: '../layouts/index', routes: [ {path: '/', component: './index'}, {path: '/about', component: './about'}, { path: '/users', component: './users/_layout', routes: [ {path: '/users', component: './users/index'}, {path: '/users/:name', component: './users/[name]'}, ] }, ] }, ], }
3、相应地,创建404组件:umi g page notfound
4、引入ant design UI库
npm i antd -S
npm i @umijs/preset-react -D (umi3升级)
1.config/config.js
export default { //路由配置 routes: [...], antd: {}, }
2.使用时需要导入组件,因为是按需加载
import {Button} from 'antd';
<Button type="success">antd Btn</Button>
引入dva
1、dva 主要是软件分层的概念
1.Page 负责与用户直接交互:渲染页面、接收用户的操作输入,侧重于展示型和交互逻辑;
2.Model 负责处理业务逻辑,可以理解成一个维护页面数据状态的对象,为 Page 做数据、状态的读写等操作;
export default { namespace: 'goods', // model的命名空间,区分多个model state: [], //初始状态 effects: { //异步操作 }, reducers: {} }
3.Service 主要负责与HTTP做接口对接,跟后端做数据交互,读写数据;
2、dva 已经融合进了 umi,在 config/config.js 中打开 dva 的开关
antd: {},
dva: {}
基本用法
umi g page goods
npm i axios -S
1、路由配置:config/config.js (如果使用约定式路由,则无须配置)
routes: [ { path: "/goods", component: "./goods" }, ]
2、在项目根目录下创建 mock/goods.js,模拟接收请求,响应数据
let data = [ {title: '单页面'}, {title: '管理项目3'} ] export default { 'get /api/goods': function(req, res){ setTimeout(() => { res.json({result: data}) }, 1000) } }
3、Model:src/models/goods,js
import axios from 'axios'; //调接口的逻辑应该放在 Service 层 function getGoods(){ return axios.get('/api/goods') } export default{ namespace: 'goods', // 命名空间,如果省略,则以文件名作为命名空间 state: [], effects: { *getList(action, {call , put}){ // 异步操作 const res = yield call(getGoods); // 发起请求 yield put({type: 'initGoods', payload: res.data.result}) // 派发异步action: initGoods } }, reducers: { initGoods(state, action){ return action.payload }, addGood(state, action){ return [...state, {title: action.payload.title}] }, delGood(state, action){ return [...state.slice(0,action.payload.index),...state.slice(action.payload.index+1)]; } } }
4、pages/goods.js
import React, { Component} from 'react'; import styles from './goods.css'; import {connect} from 'dva'; // @connect 必须放在 export default class 前面 @connect( state => ({ goodList: state.goods, // 从指定命名空间内获取state loading: state.loading // 通过loading命名空间获取加载的状态 }), { getList: () => ({ type: 'goods/getList' // action的type需要以命名空间为前缀,后跟reducer }), addGood: title => ({ type: 'goods/addGood', payload: {title} }), delGood: index => ( { type: 'goods/delGood', payload: {index} } ) } ) export default class extends Component{ componentDidMount(){ this.props.getList(); // 触发事件,发起请求,获取数据 } render(){ if(this.props.loading.models.goods){ // 命名空间goods 的请求在加载中 return <div>loading</div> } return ( <div> <ul> { this.props.goodList.map((good, index) => { return <li key={index}>{good.title}<button style={{marginLeft: '100px', marginBottom: '10px'}} onClick={() => this.props.delGood(index)}>删除</button></li> }) } </ul> <button onClick={() => this.props.addGood('商品3')}>添加</button> </div> ) } }
【常见报错问题】
1、reactjs页面无法引入umi/link
2、Path must be a string.
【Umi 三】 Umi项目启动报错:Path must be a string.
3、Cannot find module 'umi'
【Umi 四】 Cannot find module 'umi'
参考文章:umi