背景
之前GMTC 全球大前端技術大會上销部,公開了這張阿里前端框架的時間線,我們可以看到制跟,在2017.8和2017.12舅桩,阿里兩個不同的業(yè)務部門曾接連推出了兩款前端框架,Umi和Bigfish雨膨。但是在2018.6擂涛,阿里對兩個部門進行了整合,產(chǎn)出了Umi+Bigfish這樣的整合框架聊记。在2019.11月撒妈,Umi這款框架才算最終落地,經(jīng)過了兩年的整合甥雕,我們來看看這個Umi框架到底是個什么黑科技產(chǎn)品
它是什么
從大會上放出的另一張圖我們看到了踩身,我們在“刀耕火種”的時代做前端開發(fā)的時候胀茵,總是會考慮我們選擇在項目里使用 React 庫來開發(fā)的時候社露,項目的數(shù)據(jù)流方案應該怎么選擇(redux, mobx, redux-saga, redux-router,dva,等),組件庫 的選擇(antd, material design)琼娘,以及webpack打包的復雜配置等峭弟,這里的 Bigfish&um看起來像是把以前我們項目中通常會用到的一些庫整合到了一起附鸽。
既然Umi是一個框架,那就有很多“約定”的規(guī)則瞒瘸,需要我們遵守坷备,不管是在路由配置,還是在mock數(shù)據(jù)情臭,以及數(shù)據(jù)和頁面交互方面省撑,我們都能夠感受到這種潛在的“約定”。
它有什么
幕布版鏈接
之前用幕布整理了一個其中大概的內(nèi)容俯在,而且2.x與3.x版本差別還比較大竟秫,這張圖片整理的大部分是基于2.x的版本,可以粗略的看看跷乐,也可以點擊鏈接去官網(wǎng)查看肥败,Umi官網(wǎng)
它怎么用
我這里用Umi做了一個很簡陋的應用,不過基本需要包括的路由愕提,異步請求馒稍,頁面跳轉和mock數(shù)據(jù)都用到了,這里就拆分一下給大家做個演示浅侨。
登陸
這是一個很正常的登陸表單纽谒,表單的UI和驗證部分都是直接從Umi提供的工作臺上找到的基于antd的區(qū)塊,添加進項目就可以用如输,非常方便佛舱,只需要修改表單登陸事件處理的函數(shù):
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
this.props.form.validateFields((err: any, values: any) => {
if (!err) {
this.props.dispatch({
type: 'users/login',
payload: values,
});
}
});
};
這里就要提到Umi推薦使用的數(shù)據(jù)流方案Dva,它封裝并簡化了redux、redux-router挨决、redux-saga的使用難度请祖,具體想了解更多Dva的更多內(nèi)容,可以訪問Dva官網(wǎng)脖祈。
在代碼中肆捕,可以看到這里使用了redux常用的dispatch action的方式來發(fā)起登錄請求。所以我們需要有一個地方能夠handle這個action的執(zhí)行盖高,接下來看對應的modal是如何實現(xiàn)的:
export default {
namespace: 'users',
state: {
id: '',
userName: '',
friends: [],
},
reducers: {
save: (state: UserState, { payload }: { payload: UserState }) => {
return { ...state, ...payload };
},
},
effects: {
*login({ payload }: { payload: LoginRequestParams }, { call, put }: EffectsCommandMap) {
const response = yield call(loginApi, payload)
yield put({ type: 'save', payload: response });
router.push('/users');
}
},
};
在modal中我們定義了這個modal的namespace叫做users
慎陵,里面存放的數(shù)據(jù)包含id
,userName
和friends
,定義了一個叫做save
的reducer
來保存相關數(shù)據(jù)喻奥,還定義了一個叫做login
的方法來做含有副作用的操作席纽,可以看到方法中接收到payload
以后調(diào)用了call
方法來執(zhí)行了一個loginApi
,數(shù)據(jù)獲取成功后撞蚕,發(fā)起save
操作來保存返回的數(shù)據(jù)润梯,然后通過router.push
來更改路由。其中有很多Dva相關的知識,感興趣的朋友可以去了解下纺铭。再貼上loginApi中做的事情:
export const loginApi = (payload: LoginRequestParams) => {
return fetch("http://localhost:8000/api/users", {
method: "POST",
body: JSON.stringify(payload)
}).then((response: Response) => response.json())
};
這里直接請求了localhost
接口的原因是我并沒有做后端Api寇钉,所以是用了Umi本身提供的mock功能
使用mock數(shù)據(jù)來模擬應用的后端訪問。至此舶赔,一個完整的login登錄流程就出來了扫倡。當我們點擊login的時候,打開Chrome的redux插件:
可以看到這里有我們完整的action flow
竟纳,以及我們的state的變化撵溃。
當我們將數(shù)據(jù)存儲起來以后,我們在組件中如何使用store中的數(shù)據(jù)的方式和redux類似锥累,通過dva提供的connect方法征懈,傳入mapStateToProps參數(shù)即可,如:
const mapStateToProps = ({ users }: { users: UserState }) => ({
userName: users?.userName,
friends: users?.friends,
});
export default connect(mapStateToProps)(WelcomePage);
路由
在上面的代碼已經(jīng)看到了我們路由跳轉的一種方法是通過Umi提供的router.push(url)
揩悄,官方還提供一種是通過鏈接跳轉卖哎,<Link to="/user">
這種方式。
在Umi中有兩種方式來定義路由删性,一種是約定式亏娜,一種是配置式。接下來就說一下這兩種的區(qū)別:
約定式
我們在使用腳手架生成Umi項目后可以看到src的目錄里面包含了一個pages的文件夾蹬挺,umi打包的時候會將目錄之間的關系映射成路由關系维贺,如:
-
src/pages/users/index.tsx
會成為/users
-
src/pages/users/$id.tsx
會成為/users/:id
-
src/pages/users/[id]/settings.tsx
會成為/users/:id/settings
以此類推。umi打包后生成的pages/.umi/router.js
文件也可以看出來它們之間的關系巴帮,如圖:
...,
routes: [
{
path: '/404',
exact: true,
component: __IS_BROWSER
? _dvaDynamic({
component: () => import('../404.tsx'),
})
: require('../404.tsx').default,
_title: 'umi-js',
_title_default: 'umi-js',
},
{
path: '/',
exact: true,
component: __IS_BROWSER
? _dvaDynamic({
component: () => import('../index.tsx'),
})
: require('../index.tsx').default,
_title: 'umi-js',
_title_default: 'umi-js',
},
配置式
如果項目路由足夠復雜溯泣,有很多權限校驗的東西,那么Umi也提供了配置化修改榕茧。在項目中會有一個.umirc.ts
的文件垃沦,這個文件就是項目的配置文件,也可以通過config/config.ts
文件來配置用押。
const config: IConfig = {
routes: [
{ path: '/', component: './index' },
{
path: '/users',
component: './users/index',
},
{
path: 'users/detail',
component: './users/detail',
},
{ path: 'users/:id', component: './users/$id.tsx' },
],
...,
};
在配置文件里我們可以更靈活的定義我們路由肢簿,也可以添加權限路由和嵌套路由,這里就不贅述了蜻拨,有興趣可以訪問官網(wǎng)查看池充。
mock數(shù)據(jù)
當我們做前后端分離項目的時候,前后端通常不會一直都以相同速率開發(fā)缎讼,總是會有一方等待另一方集成的問題收夸。在umi中針對這種情況給了mock數(shù)據(jù)的解決方案,如圖:
在根目錄中有一個叫做mock的文件夾血崭,Umi約定在這個文件夾下的文件都被視作mock數(shù)據(jù)卧惜。當前端訪問本地接口的時候厘灼,就會到這里面來對應的查找有沒有和請求的url能夠匹配的數(shù)據(jù),如果有就直接返回序苏。
比如我的api.js文件中:
import mockjs from 'mockjs';
export default {
'POST /api/users': mockjs.mock({
userName: '@name',
id: '@id',
'friends|5-10': [{ id: '@id', userName: '@name' }],
}),
};
這里使用了mockjs
來生成對應格式的mock數(shù)據(jù)手幢,這樣可以最大限度的保證數(shù)據(jù)的有效性捷凄。
Umi-UI
這里有一個Umi的工作臺覺得需要提出來說一下忱详,因為個人覺得這個工作臺很大程度上減少了前端開發(fā)的門檻。
從上面的圖可以看出跺涤,如果你不熟悉webpack
匈睁,不熟悉配置式路由
,不熟悉npm script
桶错,在這個工作臺都能夠可視化修改航唆。甚至你可以直接把區(qū)塊和模板里的東西直接引入到你自己的項目中,無須做太多改動就可用院刁,極大減輕了UI開發(fā)的壓力糯钙。
結語
以上就是對Umi框架的一些簡單的介紹,可能大家覺得Umi 2.x有點臃腫退腥,包含的東西太多任岸。沒關系,可以嘗試Umi 3.0狡刘,更加的精簡和插件化享潜。
最后附上項目的github地址 。