背景
- React
前端三大框架之一。 - typescript
javascript的超集 - Dva
由阿里架构师 sorrycc 带领 team 完成的一套前端框架,在作者的 github 里是这么描述它的:”dva 是 react 和 redux 的最佳实践”。 - Antd
是阿里的一套开箱即用的中台前端/设计解决方案,UI框架。 - Umi
一套可插拔的企业级 react 应用框架,同样由dva作者 sorrycc 完成。他在Umi中引入了 UI 工具 antd,打包工具 roadhog,路由 react-router和状态管理器 dva,做到了可插拔机制。
创建一个umi应用
- 先安装node,再创建一个项目文件夹,通过脚手架创建umi项目
npx @umijs/create-umi-app
-
- 安装依赖
npm i
- 运行项目
npm run start
umi应用的路由
配置路由
在配置文件.umirc.ts中通过 routes 进行配置,格式为路由信息的数组。
routes: [ { path: '/', component: '@/pages/Index' }, { path: '/User', component: '@/pages/User' }, ],
路由配置工程化
为了让代码更工程化,我们可以将路由配置单独拆分成一个文件
router.tsx
const router: any = [ { path: '/', component: '@/pages/Index' }, { path: '/User', component: '@/pages/User' }, ] export default router;
.umirc.ts
import { defineConfig } from 'umi'; import router from '@/router/router'; // 引入路由配置文件 export default defineConfig({ nodeModulesTransform: { type: 'none', }, routes: router, });
约定式路由
除配置式路由外,Umi 也支持约定式路由。约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。
备注:约定式路由要先注释.umirc.ts里的routes配置
路由跳转
import { history } from 'umi'; // 跳转到指定路由 history.push('/list'); // 带参数跳转到指定路由 history.push('/list?a=b'); history.push({ pathname: '/list', query: { a: 'b', }, }); // 跳转到上一个路由 history.goBack();
示例
Index.tsx
import React, { Component } from 'react' import { history } from 'umi'; import styles from '@/assets/Style/Index.less'; // css module export default class Index extends Component { // 路由跳转不带参数 toLogin() { history.push('/login'); } // 路由跳转带参数 toLoginWithParameter() { history.push({ pathname: '/login', query: { a: 'b', }, }) } render() { return ( <div> <div className={styles.title}>首页</div> <div onClick={this.toLogin}>跳转不带参数</div> <div onClick={this.toLoginWithParameter}>跳转带参数</div> </div> ) } }
User.tsx
import React, { Component } from 'react' export default class User extends Component { constructor(props: any) { super(props); console.log(props.location.query) // 打印路由参数 } render() { return ( <div> <h1 className={styles.title}>User</h1> </div> ) } }
安装插件集@umijs/preset-react
@umijs/preset-react是包含antd,dva等一系列插件的插件集,由于使用指令npx @umijs/create-umi-app创建的项目会自动添加此插件,所以之后不需要再安装@umijs/preset-react插件集包含的插件,否则启动项目的时候会报错
umi+antd
安装了插件集@umijs/preset-react之后,无需再做任何配置,直接可以按需加载antd并在组件中使用
import React, { Component } from 'react' import { history } from 'umi'; import { Button } from 'antd'; // 引入antd组件 import styles from '@/assets/Style/Index.less'; // css module export default class Index extends Component { // 路由跳转不带参数 toUser() { history.push('/User'); } // 路由跳转带参数 toUserWithParameter() { history.push({ pathname: '/User', query: { a: 'b', }, }) } render() { return ( <div> <div className={styles.title}>首页</div> <Button type="primary" onClick={this.toUser}>跳转不带参数</Button> <Button type="primary" onClick={this.toUserWithParameter}>跳转带参数</Button> </div> ) } }
umi+dva
安装了插件集@umijs/preset-react之后,无需再做任何配置,直接可以使用dva
- 创建models目录以及model文件userInfo.tsx
import { Effect, ImmerReducer, Reducer, Subscription } from 'umi'; export interface UserInfoModelState { name: string; age: number; } export interface UserInfoModelType { namespace: 'userInfo'; state: UserInfoModelState; effects: { query: Effect; }; reducers: { save: Reducer<UserInfoModelState>; changeName: Reducer<UserInfoModelState>; // 启用 immer 之后 // save: ImmerReducer<UserInfoModelState>; }; subscriptions: { setup: Subscription }; } const UserInfoModel: UserInfoModelType = { namespace: 'userInfo', state: { name: '张三', age: 20, }, effects: { *query({ payload }, { call, put }) { }, }, reducers: { save(state, action) { return { ...state, ...action.payload, }; }, changeName(state, action) { return { ...state, ...action.payload, }; }, // 启用 immer 之后 // save(state, action) { // state.name = action.payload; // }, }, subscriptions: { setup({ dispatch, history }) { return history.listen(({ pathname }) => { if (pathname === '/') { dispatch({ type: 'query', }) } }); } } }; export default UserInfoModel;
- 组件中使用
- class组件中使用
import React, { Component } from 'react' import { connect, UserInfoModelState, Loading } from 'umi'; const connect1: any = connect; @connect1(({ userInfo, loading }: { userInfo: UserInfoModelState; loading: Loading }) => ({ userInfo, // dva-loading可以自动处理loading状态 loading: loading.models.index, })) export default class User extends Component<any, any> { constructor(props: any) { super(props); console.log(props); this.state = { username: props.userInfo.name } } // 调用userInfo模块的reducers里的changeName方法 private changeName = () => { const { dispatch } = this.props; dispatch({ type: 'userInfo/changeName', payload:{ name: '李四' } }) } render() { return ( <div> <div onClick={this.changeName}>更改用户名</div> <div className="title">用户名{this.props.userInfo.name}</div> </div> ) } }
- 函数式组件中使用
import React, { FC } from 'react'; import { UserInfoModelState, ConnectRC, Loading, connect } from 'umi'; interface PageProps { userInfo: UserInfoModelState; loading: boolean; } const IndexPage: FC<PageProps> = (props) => { const handleClick = () => { const { dispatch } : any = props; dispatch({ type: 'userInfo/changeName', payload:{ name: '李四' } }) } return ( <div> <div onClick={handleClick}>更改用户名</div> <div className="title">用户名{props.userInfo.name}</div> </div> ) }; export default connect(({ userInfo, loading }: { userInfo: UserInfoModelState; loading: Loading }) => ({ userInfo, loading: loading.models.index, }))(IndexPage);
- 项目目录
主要文章参考
https://www.icode9.com/content-4-652359.html
https://www.cnblogs.com/llcdbk/p/13029996.html
https://www.cnblogs.com/crazycode2/p/8593143.html
https://www.jianshu.com/p/86bd9fc0a219
https://segmentfault.com/q/1010000014835057
https://blog.csdn.net/YMX2020/article/details/106674097
https://blog.csdn.net/SCU_Cindy/article/details/82432971
初次尝试,摸坑永不止步,还有以下文章也参考了一下,拓展思路
https://www.cnblogs.com/jiawei-Wang/p/11400848.html
https://segmentfault.com/a/1190000021272819?utm_source=tag-newest
https://zhuanlan.zhihu.com/p/69200639
https://www.yuque.com/umijs/umi/dvamodels
https://www.codercto.com/a/25627.html
https://blog.csdn.net/deletGlobal/article/details/106183217
https://blog.csdn.net/YMX2020/article/details/106674097
https://zhuanlan.zhihu.com/p/92617879
http://www.caotama.com/294655.html
https://www.cnblogs.com/winfred/p/8216650.html
https://www.jianshu.com/p/21f8ed30e761
https://www.cnblogs.com/axel10/p/8503782.html
https://www.jianshu.com/p/81a5d4371f81
https://blog.csdn.net/sllailcp/article/details/89384328
https://www.cnblogs.com/lucas27/p/9292058.html
https://www.jianshu.com/p/c1a4166d9eda