##介紹 最近開發了一個react項目,由於以前都是作原生混合H5開發,對redux用的不怎麼熟練,此次想要鍛鍊下而後花幾天看了一下redux和看了幾個搭建方案,以及看了下公司其餘的H5項目(直接用redux的項目)以爲很複雜繁瑣。用過ant-design-pro 2.0正式版(加入了umi的版本)以爲很不錯,因此決定從UMI入手搭一個項目來作手機端的H5項目,在去掉大部分業務代碼後把這個demo拿來給你們分享一下,但願對新手搭建umi項目有必定價值。html
寫這篇文章是爲了幫助須要的人更好的理解umi來搭建項目,第一次寫文章不足之處望指正 本文的例子的demo在個人
github
地址能夠下載參考 github地址 以爲對本身理解和上手umi項目有幫助的點個starnode
##建立項目react
yarn是facebook推出的,在一些較新的react書籍和資料中也是推薦使用yarn。與npm相比,yarn主要的優點在於:速度快,離線模式,版本控制。git
yarn create umi
複製代碼
會出現一個選擇框,我選擇了antd,dll,hard source。這幾個配置在umi官網快速上手裏面有配置的解釋。 確保 node 版本是 8.10 或以上github
yarn
複製代碼
yarn start
複製代碼
umi build
複製代碼
##我對umi的一些理解express
models
,而後全部的models
寫在裏面。 用了 umi 後,能夠在pages同級下寫一個models來管理全部的models也能夠在每一個頁面的文件夾下寫一個models文件夾來放當前頁面須要用的models,好處是結構更加清晰了,刪除起來方便不須要去刪除好幾個地方,且會自動註冊 models
pages
目錄下的頁面的js自動生成路由配置。能夠參考umi官網路由部分,+ pages/
+ users/
- index.js
- index.less
- index.js
複製代碼
[
{ path: '/', component: './pages/index.js' },
{ path: '/users/', component: './pages/users/index.js' },
]
複製代碼
+ pages/
+ orderdetail/
- $id$.js
- index.less
複製代碼
import router from 'umi/router'
router.push('/orderdetail/' + val.id)
複製代碼
this.props.match.params.id
複製代碼
約定 src/layouts/index.js 爲全局路由,返回一個 React 組件,經過 props.children 渲染子組件。npm
+ layouts/
+ baseLayout/
- index.js
- index.less
- index.js
複製代碼
import React, { Component } from 'react'
import BaseLayout from './baseLayout'; // 底部導航的組件
const ULR_NO_LAYOUT = ['/', '/home', '/class', '/my']; //判斷在哪幾個路由下須要出現底部導航
class Index extends Component {
componentDidMount() {
}
renderBody = () => {
const {location: {pathname}, children } = this.props;
if (ULR_NO_LAYOUT.includes(pathname)) {
return (<BaseLayout {...this.props} />);
}
return (
<React.Fragment>
{children}
</React.Fragment>
);
}
render() {
return (
<React.Fragment>
{this.renderBody()}
</React.Fragment>
)
}
}
export default Index;
複製代碼
ULR_NO_LAYOUT
變量是爲了判斷在哪幾個路由下須要出現底部導航BaseLayout
是用 antd-mobile
的 TabBar
約定 mock 目錄裏全部的 .js 文件會被解析爲 mock 文件。咱們新建一個home.js
json
export default {
// 支持值爲 Object 和 Array
'GET /api/users': { users: [1, 2] },
// GET POST 可省略
'/api/users/1': { id: 1 },
// 支持自定義函數,API 參考 express@4
'POST /api/users/create': (req, res) => { res.end('OK'); },
};
複製代碼
直接請求/api/users
就能拿到 { users: [1, 2] }
redux
須要根據本身的項目和後臺的接收方法對請求方式進行封裝api
// body 添加token
if (newOptions.body) {
newOptions.body.__token__ = getToken();
} else {
newOptions.body = {
__token__: getToken(),
};
}
複製代碼
setUrlEncoded
方法,這樣處理方便get方法傳值的時候也能和post方法同樣穿對象,自動轉換帶在url後面} else if (newOptions.method === 'GET') {
new_url = url + '?' + setUrlEncoded(newOptions.body)
delete newOptions.body
}
//setUrlEncoded方法
export const setUrlEncoded = (obj) => {
let urlEncoded = '';
if(obj && obj instanceof Object) {
const keys = Object.keys(obj);
if(keys && keys.length) {
keys.forEach((key, index) => {
urlEncoded += `${key}=${obj[key]}`;
if(index + 1 < keys.length){
urlEncoded += '&';
}
});
}
}
return urlEncoded;
}
複製代碼
response
rc-form
import { createForm } from 'rc-form';
@createForm()
複製代碼
this.props
裏拿到form
裏的getFieldProps, getFieldError
render() {
const {form: {getFieldProps, getFieldError}, regLoading} = this.props;
<div>
<InputItem
{...getFieldProps('name', {
initialValue: '',
rules: [{
required: true,
message: '請輸入用戶名',
}],
})}
clear
error={!!getFieldError('name')}
onErrorClick={() => {
const err = getFieldError('name').join('、');
Toast.info(err, 1);
}}
placeholder='用戶名'
/>
</div>
}
複製代碼
submit(){
const {form, dispatch} = this.props;
form.validateFields((error, fieldsValue) => {
if (error) {
return;
}
dispatch({
type: 'login/submit',
payload: {
// 入參
},
callback: (res) => {
//須要實現什麼
}
});
});
}
複製代碼
import { connect } from 'dva';
@connect(({ home }) => ({ home }))
複製代碼
subscriptions
,subscriptions
的好處應該就是能夠監測全局的變化, 即便和當前頁面不相關model裏也能夠進行數據改動或者請求接口.固然你也能夠選擇在頁面中使用dispatch
import { reg } from 'services/home';
import router from 'umi/router';
export default {
namespace: 'home',
state: {
'list':{
'productList': '',
'bannerList': ''
}
},
effects: {
*reg({ payload, callback }, { call, put }) {
const response = yield call(reg, payload);
yield put({
type: 'setData',
payload: response.data
});
}
},
reducers: {
setData(state, { payload }) {
return {
...state,
list: payload,
}
}
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, search }) => {
if (pathname == '/home'||pathname == '/') {
dispatch({
type: 'reg',
});
}
});
},
},
};
複製代碼