umi
是⼀个可插拔的企业级 react 应⽤框架。
一、为什么用umi?
- 开箱即用,内置 react、react-router 等
- 类 next.js 且功能完备的路由约定,同时支持配置的路由⽅方式
- 完善的插件体系,覆盖从源码到构建产物的每个生命周期高性能,通过插件支持 PWA、以路由为单元的 code splitting 等
- 支持静态⻚面导出,适配各种环境,⽐如中台业务、⽆线业务、egg、⽀付宝钱包、云凤蝶等
- 开发启动快,⽀持⼀键开启 dll 和 hard-source- webpack-plugin 等
- 一键兼容到 IE9,基于 umi-plugin-polyfills
- 完善的 TypeScript ⽀持,包括 d.ts 定义和 umi test
- 与 dva 数据流的深⼊入融合,⽀持 duck directory、model 的⾃动加载、code splitting 等等
二、umi和dva、roadhog是什么关系?
- roadhog是基于webpack的封装工具,目的是简化webpack的配置
- umi可以简单地理解为roadhog+路由,思路类似于next.js/nuxt.js,辅助一套插件机制,目的是通过框架的方式简化React开发
- dva目前是纯粹的数据流,和umi以及roadhog之间没有依赖关系,可以分开使用、或者一起使用。个人认为umi+dva是比较搭的
dva
dva 首先是一个基于 redux 和 redux-saga 的数据流⽅案, 然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
关于dva的介绍,之前有写过一篇《为了学习dva:支付宝前端架构方案,我把它翻了个底朝天》,里面讲的会比较详细些。
一、理解dva
软件分层:回顾react,为了让数据流更易于维护,我们分成 了store,reducer,action等模块,各司其职,软件开发也是一样。
DVA 是基于 redux、redux-saga 和 react-router 的轻量级前端框架及最佳实践沉淀,核心api如下:
-
model
- state 状态
- action
- dispatch
- reducer
- effect 副作⽤,处理异步
-
subscriptions订阅
-
router路由
二、Use umi with dva
⾃>= umi@2
起,dva的整合可以直接通过umi-plugin-react
来配置。
dva+umi 的约定
- src 源码
- pages⻚面
- components 组件
- layout布局
- model
- config 配置
- mock 数据模拟
- test测试等
Umi基本使⽤
建立pages下⾯的单面about:umi g page about
建⽴文件夹more(默认是css):umi g page more/index --less
import router from 'umi/router'
跳转 router.push('/user/2')
起服务看效果:umi dev
一、路由
umi 会根据 pages ⽬录自动生成路由配置。
约定式路由
router渲染的三种方式:chirdren、conponent、render
1、基础路由
2、动态路由
umi g page product/'$id'
import styles from './$id.less';
export default function({ match }) {
return (
<div className={styles.normal}>
<h1>Page $id</h1>
<p>{match.params.id}</p>
</div>
);
}
注意:获取当前id值,框架已经帮我们传值了,props上也有context
config
{
path: '/product/:id',
component: './product/$id',
},
3、可选的动态路由:umi 里约定动态路由如果带 $ 后缀
umi g page product/'$id$'
export default function({ location, match }) { const { id } = match.params;
return (
<div className={styles.normal}>
<h1>Page $id$</h1>
<p>{id || '没有id'}</p>
</div>
);
}
config
{
path: '/channel/:id?',
component: './channel/$id$',
},
4、嵌套路由
umi 里约定⽬录下有_layout.js
时会⽣成嵌套路由,以 _layout.js 为该目录的 layout 。layout ⽂件需要返回一个React 组件,并通过props.children
渲染⼦组件。
⾸先创建``_layout.js:
umi g page ofLayout/_layout`
// 创建⽗父组件 umi g page ofLayout/_layout
export default function(props) {
return (
<div>
<h1>Page _layout</h1>
<div>{props.children}</div>
</div>
) }
创建兄弟组件 umi g page ofLayout/index
export default function() {
return (
<div className={styles.normal}>
<h1>Page index</h1>
</div>
);
}
5、全局 layout
约定src/layouts/index.js
为全局路路由,返回⼀个 React
组件,通过props.children
渲染子组件。
export default function(props) {
return (
<>
<Header />
{ props.children }
<Footer />
</>
);
}
6、不同的全局 layout
你可能需要针对不同路由输出不同的全局 layout,umi 不支持这样的配置,但你仍可以在 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 />
</>
);
}
二、在⻚面间跳转
在 umi ⾥,⻚面之间跳转有两种⽅式:声明式和命令式。
1、声明式:基于 umi/link
,通常作为 React 组件使用。
import Link from 'umi/link';
export default () => (
<Link to="/list">Go to list page</Link>
);
2、命令式:基于 umi/router
,通常在事件处理中被调用。
import router from 'umi/router';
function goToListPage() {
router.push('/list');
}
三、启⽤Hash 路由
umi 默认是⽤的 Browser History
,如果要用 Hash History
,需配置:
export default {
history: 'hash',
}