谈谈IONIC版本中加入的React开发方式
IONIC介绍
发现国内前端圈里面,现在知道IONIC的人已经很少了,但毕竟这东西也是一门不错的移动端开发技术,感觉可能大多数人对于新技术的追求和尝试,让这个技术看起来地位略微尴尬。
但是,毫无疑问,这门技术,在全球还是相对比较流行的。
IONIC是什么?如果在利用前端技术做手机app的起步阶段,大家大概会听到phonegap、Xamarin。
其中Xamarin是基于C#的一套移动开发框架,当然,现如今团队已经被微软收购,生命力看起来也并不算多顽强,喜欢C#的人可能会用到,但前端同事估计很难去接触。
而phonegap则是最初始的前端技术做手机App的开发框架,当时社区内部也有不少前端在讨论这个技术,以至于后来催生了国内前端移动化的一个趋势。
例如Dcloud、APICloud、AppCan这些国内的前端做移动App的框架,其中Dcloud和APICloud曾经还因为源码事件撕逼过一段时间,这一切都是因为phonegap这样技术催生了国内开发者的视野。
后来phonegap优化成了一部分,发展成了Cordova这门技术。
在RN还未出现的时刻,Cordova可谓是如日中天,当时我曾经也做过几个Cordova项目,在商业趋于移动化的年代,Cordova技术每个移动前端必会的技术。
而当时比较火热的技术angularjs,当时还是1.0脏检查阶段,于是结合Cordova、angularjs发展出来的移动端开发UI框架IONIC应运而生。
IONIC在angularjs在国内前端市场占据百分之九十以上市场的时候曾经也算火热一时,国内涌现了许多利用该技术制作的App。
但,angularjs后来被新兴的单向数据流技术React抢占了大量的市场,以至于市场份额落后到了百分之十左右程度,导致IONIC也受到了发展局限,性能问题频出。
更别说后来React Native的出现,利用JS写原生组件这个概念当时甚嚣尘上,我当时的公司也有将App专项RN开发的想法。
虽然后来Angular更新换代,有了2.0、4和Angular5,性能得到了很大的提升,避免了过量脏检查机制,但好似错过了黄金年代,市场份额则是不愠不火。
IONIC从2018年开始集成React技术,并且在2019年可以投入使用,中间一直是Angular和TS在支撑着平台前进。
但说到底,IONIC只是开发浏览器应用,而不是真正的原生应用,和React Native有很大的区别的。
不过,最近随着大家手机性能的提升,其实原生应用和浏览器应用,在性能上几乎是看不出差异,但如今国内前端圈很多人只知道React Native、Flutter而不知IONIC,实在是有些尴尬。
最近我也重新捡起这门技术,看看这个React应用到底在IONIC上做了哪些事情。
React + TypeScript
IONIC的React引入,同样和Angular一样,都是利用TypeScript做类型检查。并且直接引入的React的高级版本,现如今支持FC和Hooks特性。
下面来一段生成的应用中的代码:
const App: React.FunctionComponent = () => (
<IonApp>
<IonReactRouter>
<IonPage id="main">
<IonTabs>
<IonRouterOutlet>
<Route path="/:tab(books)" component={Books}/>
<Route path="/:tab(home)" component={Home} exact={true} />
<Route path="/:tab(books)/details" component={Details} />
<Route path="/:tab(cate)" component={Categaray} />
<Route exact path="/" render={() => <Redirect to="/home" />} />
</IonRouterOutlet>
<IonTabBar slot="bottom">
<IonTabButton tab="schedule" href="/books">
<IonIcon icon={book} />
<IonLabel>书架</IonLabel>
</IonTabButton>
<IonTabButton tab="speakers" href="/home">
<IonIcon icon={apps} />
<IonLabel>书城</IonLabel>
</IonTabButton>
<IonTabButton tab="map" href="/cate">
<IonIcon icon={send} />
<IonLabel>分类</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
</IonPage>
</IonReactRouter>
</IonApp>
);
组件化
IONIC是个UI框架,已经把组建平台分装成了React组件,可以直接引用就可。
import { RouteComponentProps } from 'react-router';
import { IonItem, IonLabel, IonList, IonThumbnail, IonContent } from '@ionic/react';
不过,我尝试写了一个组件,引入发生报错信息:
Type '{}' is missing the following properties from type 'Readonly<RouteComponentProps<{}, StaticContext, any>>': history, location, matchts(2739)
可见,在IONIC下写一些组件,似乎是失去了自由,感觉略微有些尴尬,这个组件化似乎是不彻底?
不过,在项目中可以直接用div去写当前组件,但这样似乎是不能共用?
稍等,这是TypeScript的校验,于是我们需要做一些修改:
import { Header } from '../../components'
interface props {
Header?: PureComponent
}
class Home extends React.PureComponent<props, {}> {}
Header组件经过改造终于可以用了,那么,我们就可以通过写Web的方式,来开发移动端的应用了。
工程化
1、Icon
对一个对应用有想法的人,ionicons满足不了项目需求,于是,这个时候可以选择引入iconfont或者font asome
因为我并不是美工,也没人上传到iconfont一些图标,于是我选择引入fontasome:
直接在public/index.html以CDN的方式引入:
<link href="http://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
项目中直接用:
<i className="fa fa-home fa-fw"></i>
<i className="fa fa-book fa-fw"></i>
2、Request
利用fetch添加通用请求方式(其实也可以用别的):
import _ from 'lodash'
interface HttpProps {
url: string,
method: string,
body: object
}
export default function httpRequest(httpProps: HttpProps) {
const init = {
method: httpProps.method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Accept-language': 'zh-CN',
},
body: ''
}
if (httpProps.method !== 'GET') {
init.body = JSON.stringify(httpProps.body);
}
return fetch(httpProps.url, init).then(checkStatus, (err) => console.warn('===>request checkStatus error', err)).then(
(val) => {
const result = val.json();
console.log(
`%c fetch end: ${httpProps.url}`,
'color: green;font-size: 14px;font-weight:bold;',
result,
);
return result;
},
(err) => {
console.warn('===>parse json error', err);
},
).catch((err) => {
console.error('###ERROR###', err);
});
}
function checkStatus(response: any) {
const status = _.get(response, 'status');
if (status >= 200 && status < 300) {
return response;
}
throw new Error('status wrong');
}
请求文件可以直接用这个写好的封装:
// import _ from 'lodash';
import { config, httpRequest } from '../utils';
interface ReturnProps{
result: object,
}
interface RequestBody {
url: string
}
export default class HttpService<ReturnProps, RequestBody> {
getHomePages = async (requestBody: RequestBody) => {
const url = config.baseUrl;
const result = await httpRequest({url, method: 'GET', body: {}})
console.log('result==============>', result)
return result
}
}
这个时候,是不是想要引入Redux?
3、Redux
在引入Redux主要是通过saga这种方式,这时候基本上要添加的是sagas、reducer、actions。
首先添加Actions:
export const FAIL_GETHOME = 'FAIL_GETHOME'
export const SUCCESS_GETHOME = 'SUCCESS_GETHOME'
export const GET_HOMEDATA = 'GET_HOMEDATA'
添加Reducers:
// import _ from 'lodash';
import { FAIL_GETHOME, SUCCESS_GETHOME, GET_HOMEDATA } from '../actions/home';
const initState = {
loading: false
}
export default function homeReducer(state = initState, action: any) {
if (action.type === GET_HOMEDATA) {
return {
...state,
loading: true,
};
} else if (action.type === SUCCESS_GETHOME) {
return {
...state,
loading: false,
};
} else if (action.type === FAIL_GETHOME) {
return {
...state,
loading: false,
};
}
return state;
}
添加sagas处理请求:
import _ from 'lodash';
import { call, put, takeEvery } from 'redux-saga/effects';
import { FAIL_GETHOME, SUCCESS_GETHOME, GET_HOMEDATA } from '../actions/home';
import HttpService from '../services/http-service';
function* getHomeData(action: any) {
const key = _.get(action, 'key');
const httpSerice = new HttpService()
try {
const data = yield call(httpSerice.getHomePages, action.payload);
if (!data) {
yield put({ type: FAIL_GETHOME, status: 2, key });
} else {
yield put({ type: SUCCESS_GETHOME, status: 0, payload: data, key });
}
} catch (e) {
yield put({ type: FAIL_GETHOME, status: 1, key });
}
}
export function* watchGetHomeData() {
yield takeEvery(GET_HOMEDATA, getHomeData)
}
到这里一个基本的Redux流程添加完毕。接下来可以在项目中触发Actions,来进行数据请求了。
IONIC和RN
最后谈谈IONIC这门技术和React Native的区别。
两者都是基于某种技术的一种UI开发App方式,IONIC的组件相对比较完善,RN的组件则是比较简单。
开发方式来说,IONIC则是浏览器开发方式,相当于是开发的是一个webapp,但是RN开发出来的是原生应用。这是两者主要的技术区别。
上手来说,毫无疑问,IONIC的开发上手起来更快,其实是IONIC的开发就是普通的web+UI框架开发,而RN则还有些前置理解成本。
总的来说,现如今性能方面渐渐被日渐性能提升的手机抹平,其实在这个时候,回过头再看IONIC,也是一种不错的选择,不是吗?