介绍umi
初探
对比以往使用的 create-react-app
搭建react项目,根据需要我们还得集合webpack打包,或者引入redux状态管理器等,而umi ---
通过 create-umi提供脚手架能力,
然后我们可以选择需要生成的项目类型:
- app,通用项目脚手架,支持选择是否启用 TypeScript,以及 umi-plugin-react 包含的功能
- ant-design-pro,仅包含 ant-design-pro 布局的脚手架,具体页面可通过 umi block 添加
- block,区块脚手架
- plugin,插件脚手架
- library,依赖(组件)库脚手架,基于 umi-plugin-library
之后选择是否需要支持typescript
然后选择需要的功能: - antd: UI框架,启用后实现antd, antd-mobile 和 antd-pro 的按需编译,无需要手动配置。
- dva: 基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架
- code splitting: 是否代码分包
- dll: 通过 webpack 的 dll 插件预打包一份 dll 文件来达到二次启动提速的目的
按上下箭头移动,并按 空格 键选中。
确定后,会根据选择自动创建好目录和文件
安装依赖,yarn start
启动项目。
路由
umi 以路由为基础的,支持类 next.js 的约定式路由
,以及各种进阶的路由功能,并以此进行功能扩展,比如支持路由级的按需加载
。
(1) 无需手动配置路由
根据pages目录自动生成路由配置,会根据 src / pages 下 文件名自动生成路由
(也可以配置.umirc.js中的 routes 属性,此配置项存在时则不会对 src/pages 目录做约定式的解析)
(2) 其他基础知识:
-
动态路由:带 $ 前缀的目录或文件。
目录结构:+ pages/ + $post/ - index.js - comments.js + users/ $id.js - index.js
会生成的路由配置:
[ { path: '/', component: './pages/index.js' }, { path: '/users/:id', component: './pages/users/$id.js' }, { path: '/:post/', component: './pages/$post/index.js' }, { path: '/:post/comments', component: './pages/$post/comments.js' }, ]
可选的动态路由:
约定动态路由如果带 $ 后缀,则为可选动态路由。
(3)常用的路由操作
import Link from 'umi/link';
import router from 'umi/router';
普通使用
<Link to="/list">跳转</Link>
带参数
<Link to="/list?a=b">跳转</Link>
包含子组件
<Link to="/list?a=b"><button>跳转</button></Link>
点击跳转
<button onClick={() => router.push('/list')}>跳转</button>
-
router.push
// 普通跳转,不带参数 router.push('/list'); // 带参数 router.push('/list?a=b'); router.push({ pathname: '/list', query: { a: 'b' } });
router.replace
router.go(n)
往前或者往后跳指定页数。router.goBack()
后退一页-
umi/redirect
重定向import Redirect from 'umi/redirect'; <Redirect to="/login" />;
withRouter
当组件需要路由参数时,使用withRouter
可以给当前组件传入路由参数,将react-router的history、location、match三个对象传入props对象上,此时就可以使用this.props
布局
(1)全局layout
约定 src/layouts/index.js 为全局路由,返回一个 React 组件,通过 props.children 渲染子组件。
比如:
export default function(props) {
return (
<>
<Header />
{ props.children }
<Footer />
</>
);
}
(2)不同的全局layout
可以在 layouts/index.js 对 location.path 做区分,渲染不同的 layout 。
比如想要针对 /login 输出简单布局:
export default function(props) {
if (props.location.pathname === '/login') {
return <SimpleLayout>{ props.children }</SimpleLayout>
}
return (
<>
<Header />
{ props.children }
<Footer />
</>
);
}
(3)尝试
要求: 登录页和首页显示不同的布局
同样对 location.path 做区分,但是如果是动态路由或者嵌套路由这样的匹配是有漏洞的。
优化后:
配置路由对应的布局,默认使用NavigatorLayout
const routeLayoutMap = [{
matches: ['/users', '/login', '/contact-sale'],
component: BlankLayout,
}, {
matches:[],
component: NavigatorLayout,
}];
const res = routeLayoutMap.find(({ matches }) => {
return checkRouteMatch(matches, location.pathname)
});
const layout = res ? res.component : NavigatorLayout
return React.createElement(layout, props);
}
根据正则判断
function checkRouteMatch (routes, pathname) {
const _routes = routes.map(one => {
if (isString(one) || isRegExp(one)) one = { match: one }
if (!isObject(one)) return {}
const { match, exclude } = one
return {
match,
exclude: (isArray(exclude) || !exclude) ? exclude : [exclude]
};
})
return _routes.some(({ match, exclude }) => {
function check (rule, value) {
if (isString(rule)) return value.includes(rule);
if (isRegExp(rule)) return rule.test(value);
return false;
}
const res = check(match, pathname)
if (!res) return false;
if (!isArray(exclude) || !exclude.length) return res;
return !exclude.some(one => check(one, pathname))
})
}
mock
用之前先把mock使用示例看看==>mock.js文档
(1)在umi中使用mock:
-
新建mock数据:
在 mock 文件下新建文件 users.js 为保存mock数据的一个文件。import mockjs from 'mockjs'; let dataSource = mockjs.mock({ 'list|15-30': [{ 'id': () => mockjs.Random.guid(), 'name': /[a-zA-Z0-9]{4,8}/, 'email': /[a-zA-Z0-9]{4,8}@test\.com/, 'website': /[a-zA-Z0-9]{4,8}/ }] }).list; export default { 'GET /api/users': (req, res) => { const { page = 0, size = 10 } = req.query const _page = parseInt(page, 10) const _size = parseInt(size, 10) const data = dataSource.slice(_page * _size, (_page + 1) * _size); res.json({ content: data, number: _page, size: _size, totalElements: dataSource.length, }) }, }
调用数据
输入路径可直接获取数据,:/api/users
排除 mock 目录下不作 mock 处理的文件。
在config/config.start-dev.js文件中使用exclude
mock: {
exclude: ['mock/login.js']
},