亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

React Native項目框架搭建的一些心得體會

 更新時間:2021年05月28日 09:34:58   投稿:mrr  
React Native使你能夠在Javascript和React的基礎(chǔ)上獲得完全一致的開發(fā)體驗,構(gòu)建世界一流的原生APP。接下來通過本文給大家分享React Native項目框架搭建的一些心得體會,感興趣的朋友跟隨小編一起看看吧

React Native 是Facebook于2015年4月開源的跨平臺移動應(yīng)用開發(fā)框架, 短短的一兩年的發(fā)展就已經(jīng)有很多家公司支持并采用此框架來搭建公司的移動端的應(yīng)用,
React Native使你能夠在Javascript和React的基礎(chǔ)上獲得完全一致的開發(fā)體驗,構(gòu)建世界一流的原生APP。

項目框架與項目結(jié)構(gòu)

1. 項目中使用的技術(shù)棧

react native、react hook、typescript、immer、tslint、jest等.

都是比較常見的,就不多做介紹了

2. 數(shù)據(jù)處理使用的是react hook中的useContext+useReducer

思想與redux是一致的,用起來相對比較簡單,適合不太復(fù)雜的業(yè)務(wù)場景.

const HomeContext = createContext<IContext>({
  state: defaultState,
  dispatch: () => {}
});
const ContextProvider = ({ urlQuery, pageCode }: IProps) => {
  const initState = getInitState(urlQuery, pageCode);
  const [state, dispatch]: [IHomeState, IDispatch] = useReducer(homeReducer, initState);

  return (
    <HomeContext.Provider value={{ state, dispatch }}>
      <HomeContainer />
    </HomeContext.Provider>
  );
};
const HomeContainer = () => {
const { dispatch, state } = useContext(HomeContext);
...

3. 項目的結(jié)構(gòu)如下

|-page1
    |-handler   // 處理邏輯的純函數(shù),需進行UT覆蓋
    |-container // 整合數(shù)據(jù)、行為與組件
    |-component // 純UI組件,展示內(nèi)容與用戶交互,不處理業(yè)務(wù)邏輯
    |-store     // 數(shù)據(jù)結(jié)構(gòu)不能超過3層,可使用外部引用、冗余字段的方式降低層級
    |-reducer   // 使用immer返回新的數(shù)據(jù)(immutable data)
    |-...
|-page2
|-...

項目中的規(guī)范

1. Page

整個項目做為一個多頁應(yīng)用,最基本的拆分單元是page.

每一個page有相應(yīng)的store,并非整個項目使用一個store,這樣做的原因如下:

  • 各個頁面的邏輯相對獨立
  • 各個頁面都可作為項目入口
  • 結(jié)合RN頁面生命周期進行數(shù)據(jù)處理(避免數(shù)據(jù)初始化、緩存等一系列問題)

各個頁面中與外部相關(guān)的操作,都在Page組件中定義

  • 頁面跳轉(zhuǎn)邏輯
  • 回退之后要處理的事件
  • 需要操作哪些storage中的數(shù)據(jù)
  • 需要請求哪些服務(wù)等等

Page組件的主要作用

以其自身業(yè)務(wù)模塊為基礎(chǔ),把可以抽象出來的外部依賴、外部交互都集中到此組件的代碼中.

方便開發(fā)人員在進行各個頁面間邏輯編寫、問題排查時,可根據(jù)具體頁面+數(shù)據(jù)源,準確定位到具體的代碼.

2. reducer

在以往的項目中,reducer中可能會涉及部分數(shù)據(jù)處理、用戶行為、日志埋點、頁面跳轉(zhuǎn)等等代碼邏輯.

因為在開發(fā)人員寫代碼的過程中,發(fā)現(xiàn)reducer作為某個處理邏輯的終點(更新了state之后,此次事件即為結(jié)束),很適合去做這些事情.

隨著項目的維護,需求的迭代,reducer的體積不斷的增大.

因為缺乏條理,代碼量又龐大,再想去對代碼進行調(diào)整,只會困難重重.

讓你去維護這樣的一個項目,可想而知,將會是多么的痛苦.

為此,對reducer中的代碼進行了一些減法:

  • reducer中只對state的數(shù)據(jù)進行修改
  • 使用immer的produce產(chǎn)生immutable data
  • 冗余單獨字段的修改,進行整合,枚舉出頁面行為對應(yīng)的action

reducer的主要作用

以可枚舉的形式,匯總出頁面中所有操作數(shù)據(jù)的場景.

在其本身適用于react框架的特性之外,賦予一定的業(yè)務(wù)邏輯閱讀屬性,在不依賴UI組件的情況下,可大致閱讀出頁面中的所有數(shù)據(jù)處理邏輯.

// 避免dispatch時進行兩次,且定義過多單字段的更新case
// 整合此邏輯后,與頁面上的行為相關(guān)聯(lián),利于理解、閱讀
case EFHListAction.updateSpecifyQueryMessage:
    return produce(state, (draft: IFHListState) => {
        draft.specifyQueryMessage = payload as string;
        draft.showSpecifyQueryMessage = true;
    });    
case EFHListAction.updateShowSpecifyQueryMessage:
    return produce(state, (draft: IFHListState) => {
        draft.showSpecifyQueryMessage = payload as boolean;
    });

3. handler

這里先引入一個純函數(shù)的概念:

一個函數(shù)的返回結(jié)果只依賴于它的參數(shù),并且在執(zhí)行過程里面沒有副作用,我們就把這個函數(shù)叫做純函數(shù).

把盡可能多的邏輯抽象為純函數(shù),然后放入handler中:

  • 涵蓋較多的業(yè)務(wù)邏輯
  • 只能是純函數(shù)
  • 必須進行UT覆蓋

handler的主要作用

負責(zé)數(shù)據(jù)源到store、container到component、dispatch到reducer等等場景下的邏輯處理.

作為各類場景下,邏輯處理函數(shù)的存放地,整個文件不涉及頁面流程上的關(guān)聯(lián)關(guān)系,每個函數(shù)只要滿足其輸入與輸出的使用場景,即可復(fù)用,多用于container文件中.

export function getFilterAndSortResult(
  flightList: IFlightInfo[],
  filterList: IFilterItem[],
  filterShare: boolean,
  filterOnlyDirect: boolean,
  sortType: EFlightSortType
) {
  if (!isValidArray(flightList)) {
    return [];
  }

  const sortFn = getSortFn(sortType);
  const result = flightList.filter(v => doFilter(v, filterList, filterShare, 1, filterOnlyDirect)).sort(sortFn);

  return result;
}
describe(getFilterAndSortResult.name, () => {
  test('getFilterAndSortResult', () => {
    expect(getFilterAndSortResult(flightList, filterList, false, EFlightSortType.PriceAsc)).toEqual(filterSortResult);
  });
});

4. Container

由上面的項目結(jié)構(gòu)圖可以看出,每個Page都有base Container,作為數(shù)據(jù)處理的中心.

在此base Container之下,會根據(jù)不同模塊,定義出各個子Container:

  • 生命周期處理(初始化時要進行的一些異步操作)
  • 為渲染組件Components提供數(shù)據(jù)源
  • 定義頁面中的行為函數(shù)

Container的主要作用

整個項目中,各種數(shù)據(jù)、UI、用戶行為的匯合點,要盡可能的把相關(guān)的模塊抽離出來,避免造成代碼量過大,難以維護的情況.

Container的定義應(yīng)以頁面展示的模塊進行抽象.如Head Contianer、Content Container、Footer Container等較為常見的劃分方式.

一些頁面中相對獨立的模塊,也應(yīng)該產(chǎn)出其對應(yīng)的Container,來內(nèi)聚相關(guān)邏輯,如贈送優(yōu)惠券模塊、用戶反饋模塊等.

特別注意的是行為函數(shù)

  • 多個Container中公用的行為,可直接放入base Container中
  • 在上文架構(gòu)圖中的action事例(setAction)為另外一種行為復(fù)用,根據(jù)具體的場景進行應(yīng)用

利于代碼閱讀,A模塊的浮層展示邏輯,B模塊使用時
模塊產(chǎn)生的先后順序,先有A模塊再有B模塊需要使用A的方法

  • 定義數(shù)據(jù)埋點、用戶行為埋點
  • 頁面跳轉(zhuǎn)方法的調(diào)用(Page-->base Container-->子Container)
  • 其他副作用的行為
const OWFlightListContainer = () => {
    // 通過Context獲取數(shù)據(jù)
    const { state, dispatch } = useContext(OWFlightListContext);
    ...

    // 初次加載時進行超時的倒計時
    useOnce(overTimeCountDown);
    ...
    
    // 用戶點擊排序
    const onPressSort = (lastSortType: EFlightSortType, isTimeSort: boolean) => {
        // 引用了handler中的getNextSortType函數(shù)
        const sortType = getNextSortType(lastSortType, isTimeSort);
        dispatch({ type: EOWFlightListAction.updateSortType, payload: sortType });
        
        // 埋點操作
        logSort(state, sortType);
    };
    
    // 渲染展示組件
    return <.../>;
}

小結(jié)

由easy to code到easy to read
在整個項目中,定義了很多規(guī)范,是想在功能的實現(xiàn)之上,更利于項目人員的維護.

  • Page組件中包含頁面相關(guān)的外部依賴
  • reducer枚舉出所有對頁面數(shù)據(jù)操作的事件
  • handler中集合了業(yè)務(wù)邏輯的處理,以純函數(shù)的實現(xiàn)及UT的覆蓋,確保項目質(zhì)量
  • Container中的行為函數(shù),定義出所有與用戶操作相關(guān)的事件,并記錄埋點數(shù)據(jù)
  • Componet中避免出現(xiàn)業(yè)務(wù)邏輯的處理,只進行UI展示,減少UI自動化case,增加UT的case

規(guī)范的定義是比較容易的,想要維護好一個項目,更多的是依靠團隊的成員,在達成共識的前提下,持之以恒的堅持了

分享幾個實用的函數(shù)

根據(jù)對象路徑取值

/**
 * 根據(jù)對象路徑取值
 * @param target {a: { b: { c: [1] } } }
 * @param path 'a.b.c.0'
 */
export function getVal(target: any, path: string, defaultValue: any = undefined) {
  let ret = target;
  let key: string | undefined = '';
  const pathList = path.split('.');

  do {
    key = pathList.shift();
    if (ret && key !== undefined && typeof ret === 'object' && key in ret) {
      ret = ret[key];
    } else {
      ret = undefined;
    }
  } while (pathList.length && ret !== undefined);

  return ret === undefined || ret === null ? defaultValue : ret;
}

// DEMO
const errorCode = getVal(result, 'rstlist.0.type', 0);

讀取根據(jù)配置信息

// 在與外部對接時,經(jīng)常會定義一些固定結(jié)構(gòu),可擴展性的數(shù)據(jù)列表
// 為了適應(yīng)此類契約,便于更好的閱讀與維護,總結(jié)出了以下函數(shù)
export const GLOBAL_NOTE_CONFIG = {
  2: 'refund',
  3: 'sortType',
  4: 'featureSwitch'
};

/**
 * 根據(jù)配置,獲取attrList中的值,返回json對象類型的數(shù)據(jù)
 * @private
 * @memberof DetailService
 */
export function getNoteValue<T>(
  noteList: Array<T> | undefined | null,
  config: { [_: string]: string },
  keyName: string = 'type'
) {
  const ret: { [_: string]: T | Array<T> } = {};

  if (!isValidArray(noteList!)) {
    return ret;
  }

  //@ts-ignore
  noteList.forEach((note: any) => {
    const typeStr: string = (('' + note[keyName]) as unknown) as string;

    if (!(typeStr in config)) {
      return;
    }

    if (note === undefined || note === null) {
      return;
    }

    const key = config[typeStr];

    // 有多個值時,改為數(shù)組類型
    if (ret[key] === undefined) {
      ret[key] = note;
    } else if (Array.isArray(ret[key])) {
      (ret[key] as T[]).push(note);
    } else {
      const first = ret[key];
      ret[key] = [first, note];
    }
  });

  return ret;
}

// DEMO
// 適用于外部定義的一些可擴展note節(jié)點列表的取值邏輯
const { sortType, featureSwitch } = getNoteValue(list, GLOBAL_NOTE_CONFIG, 'ntype');


 

多條件數(shù)組排序

/**
 * 獲取用于排序的sort函數(shù)
 * @param fn 同類型元素比較函數(shù),true為排序優(yōu)先
 */
export function getSort<T>(fn: (a: T, b: T) => boolean): (a: T, b: T) => 1 | -1 | 0 {
  return (a: T, b: T): 1 | -1 | 0 => {
    let ret = 0;

    if (fn.call(null, a, b)) {
      ret = -1;
    } else if (fn.call(null, b, a)) {
      ret = 1;
    }

    return ret as 0;
  };
}

/**
 * 多重排序
 */
export function getMultipleSort<T>(arr: Array<(a: T, b: T) => 1 | -1 | 0>) {
  return (a: T, b: T) => {
    let tmp;
    let i = 0;

    do {
      tmp = arr[i++](a, b);
    } while (tmp === 0 && i < arr.length);

    return tmp;
  };
}

// DEMO
const ageSort = getSort(function(a, b) {
  return a.age < b.age;
});

const nameSort = getSort(function(a, b) {
  return a.name < b.name;
});

const sexSort = getSort(function(a, b) {
  return a.sex && !b.sex;
});

//判斷條件先后順序可調(diào)整
const arr = [nameSort, ageSort, sexSort];

const ret = data.sort(getMultipleSort(arr));

以上就是React Native項目框架搭建的一些心得體會的詳細內(nèi)容,更多關(guān)于React Native項目框架搭建的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解React開發(fā)中使用require.ensure()按需加載ES6組件

    詳解React開發(fā)中使用require.ensure()按需加載ES6組件

    本篇文章主要介紹了詳解React開發(fā)中使用require.ensure()按需加載ES6組件,非常具有實用價值,需要的朋友可以參考下
    2017-05-05
  • react-native fetch的具體使用方法

    react-native fetch的具體使用方法

    本篇文章主要介紹了react-native fetch的具體使用方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • React項目配置prettier和eslint的方法

    React項目配置prettier和eslint的方法

    這篇文章主要介紹了React項目配置prettier和eslint的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • React?Hook?Form?優(yōu)雅處理表單使用指南

    React?Hook?Form?優(yōu)雅處理表單使用指南

    這篇文章主要為大家介紹了React?Hook?Form?優(yōu)雅處理表單使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 如何利用React實現(xiàn)圖片識別App

    如何利用React實現(xiàn)圖片識別App

    圖片識別這個功能在很多app中都有,下面這篇文章主要給大家介紹了關(guān)于如何利用React實現(xiàn)圖片識別App的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-01-01
  • hooks中useEffect()使用案例詳解

    hooks中useEffect()使用案例詳解

    這篇文章主要介紹了hooks中useEffect()使用總結(jié),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • React學(xué)習(xí)筆記之列表渲染示例詳解

    React學(xué)習(xí)筆記之列表渲染示例詳解

    最近在學(xué)習(xí)React,學(xué)習(xí)到了列表渲染這一塊,發(fā)現(xiàn)網(wǎng)上這方面的資料較少,所以自己來總結(jié)下,下面這篇文章主要給大家介紹了關(guān)于React學(xué)習(xí)筆記之列表渲染的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • React技巧之中斷map循環(huán)的方法詳解

    React技巧之中斷map循環(huán)的方法詳解

    這篇文章主要和大家來分享一下React的技巧之如何中斷map循環(huán),文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解一下
    2023-06-06
  • React為什么需要Scheduler調(diào)度器原理詳解

    React為什么需要Scheduler調(diào)度器原理詳解

    這篇文章主要為大家介紹了React為什么需要Scheduler調(diào)度器原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • GraphQL在react中的應(yīng)用示例詳解

    GraphQL在react中的應(yīng)用示例詳解

    這篇文章主要為大家介紹了GraphQL在react中的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10

最新評論