談談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,也是一種不錯的選擇,不是嗎?

 

我的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM