欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

react后臺系統(tǒng)最佳實(shí)踐示例詳解

 更新時(shí)間:2023年01月03日 17:21:24   作者:Keefer68721  
這篇文章主要為大家介紹了react后臺系統(tǒng)最佳實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、中后臺系統(tǒng)的技術(shù)棧選型

本文主要講三塊內(nèi)容:中后臺系統(tǒng)的技術(shù)棧選型、hooks時(shí)代狀態(tài)管理庫的選型以及hooks的使用問題與解決方案。

1. 要做什么

我們的目標(biāo)是搭建一個適用于公司內(nèi)部中后臺系統(tǒng)的前端項(xiàng)目最佳實(shí)踐。

2. 要求

由于業(yè)務(wù)需求比較多,一名開發(fā)人員需要負(fù)責(zé)幾個后臺系統(tǒng)。所以項(xiàng)目最佳實(shí)踐的要求按重要性排行:

1、開發(fā)效率。

2、可維護(hù)性。

3、性能。

總之,開發(fā)的高效率跟簡單的代碼結(jié)構(gòu)是比較側(cè)重的兩點(diǎn)。

3. 技術(shù)棧怎么選

由于我司前端技術(shù)棧主要使用React,所以基礎(chǔ)框架采用React跟React-router。項(xiàng)目開發(fā)內(nèi)容主要是做中后臺系統(tǒng)頁面,于是選擇antd作為系統(tǒng)的UI框架。然后ahooks提供了useAntdTable方法可以幫助我們節(jié)省二次封裝的工作量,所以采用ahooks作為項(xiàng)目主要使用的hooks庫。最后考慮到開發(fā)效率以及性能,狀態(tài)管理庫則采用MobX。

下面詳細(xì)說一下狀態(tài)管理庫的選型過程。

二、hooks時(shí)代狀態(tài)管理庫的選型

如果使用了ahooks或者React-Query這類帶數(shù)據(jù)請求方案的hooks庫,那已經(jīng)分擔(dān)了狀態(tài)管理庫很大一部分工作了。剩下的部分是頁面的交互狀態(tài)處理問題,主要是解決跨組件通信的問題。

目前調(diào)研的狀態(tài)管理方案有以下幾種:

context

首先考慮的是不引入任何狀態(tài)管理庫,直接使用React框架提供的context方法。

React context表面上使用起來很方便,只要定義一個provider并傳入數(shù)據(jù),使用的時(shí)候用useContext獲取對應(yīng)的值即可。

但這個方案需要開發(fā)者考慮如何處理組件重復(fù)渲染的問題,需要開發(fā)者考慮是通過手動拆分provider的數(shù)據(jù)還是使用memo、useMemo緩存組件的方案(詳情見這里)。

總的來說解決起來還是比較麻煩的,每次添加狀態(tài)都要檢查這個值是否要拆分、是否頻繁更新以及怎么組織組件比較合理等問題。

總結(jié):React context開發(fā)效率不高、后期維護(hù)麻煩。

// 需要拆分狀態(tài)
<UserContext.Provider value={userData}>
  <MenuContext.Provider value={menuData}>
    {props.children}
  </MenuContext.Provider>
</UserContext.Provider>
// 需要緩存組件
useMemo(() => <Component value={a} />, [a])

redux

接下來是目前React狀態(tài)管理庫中下載量最高的redux。

redux這個方案首先要吐槽的是其繁瑣的寫法。每次使用的時(shí)候都要煩惱action怎么取名;使用reducer時(shí)要寫一大堆擴(kuò)展運(yùn)算符,而且一個請求至少要寫三個狀態(tài)(發(fā)送請求、請求成功、請求失敗);異步用thunk會被嫌棄不夠優(yōu)雅,而saga的API又多generator寫法又不好用。

官方的推出的Redux Toolkit框架解決了上面說的action的命名問題,還有reducer的要寫一堆擴(kuò)展運(yùn)算符的問題。但狀態(tài)顆粒度太細(xì)的問題還是存在,saga的寫法也還是沒變。

如果結(jié)合ahooks的話剛好是可以把saga節(jié)省掉,但用了這些請求庫之后redux鼓吹的狀態(tài)跟蹤的優(yōu)點(diǎn)也就消失了大半~~(雖然感覺這個功能也沒啥作用)~~。只是單純解決跨組件通信的話引入Redux Toolkit又感覺太重了,而

且對比其他狀態(tài)庫Redux Toolkit使用起來還是不夠簡便。

總結(jié):redux是真的繁瑣繁瑣繁瑣。

// 代碼來源網(wǎng)上的[案例](https://codesandbox.io/s/react-ts-redux-toolkit-saga-knq31?file=/src/api/user/userSlice.ts:1752-1761)
// 這一坨代碼實(shí)現(xiàn)的功能隨便換個庫就只要幾行就搞定
export const createSagaAction = <
  PendingPayload = void,
  FulfilledPayload = unknown,
  RejectedPayload = Error
>(typePrefix: string): SagaAction<PendingPayload, FulfilledPayload, RejectedPayload> => {
  return {
    request: createAction<PendingPayload>(`${typePrefix}/request`),
    fulfilled: createAction<FulfilledPayload>(`${typePrefix}/fulfilled`),
    rejected: createAction<RejectedPayload>(`${typePrefix}/rejected`),
  }
}
export const fetchUserAction = createSagaAction<
 User['id'],
 User
>('user/fetchUser');
export function* fetchUser(action: PayloadAction<User['id']>) {
  try {
    const user = yield call(getUser, action.payload);
    yield put(fetchUserAction.fulfilled(user));
  } catch (e) {
    yield put(fetchUserAction.rejected(e));
  }
}
export function* userSaga() {
  yield takeEvery(fetchUserAction.request.type, fetchUser);
}
export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {},
  extraReducers: (builder) => (
    builder
      .addCase(fetchUserAction.request, (state) => {
        state.isLoading = true;
      })
      .addCase(fetchUserAction.fulfilled, (state, action) => {
        state.isLoading = false;
        state.user = action.payload;
      })
      .addCase(fetchUserAction.rejected, (state, action) => {
        state.isLoading = false;
        state.error = action.payload;
      })
  )
});

recoil

官方還推薦了一個叫recoil的狀態(tài)管理庫,使用了下感覺也不夠簡便。

定義狀態(tài)有兩個常用的api:atom跟selector。atom每次使用都要寫key,selector用著感覺也有點(diǎn)冗余。調(diào)用的api還分useRecoilState跟useRecoilValue,從簡便性來說被下面要講的zustand完爆。

然后這個框架本身也比較新,npm下載量也比zustand要低不少。

總結(jié):簡便性被zustand完爆,下載量不高。

// 定義分atom跟selector
const a = atom({
  key: "a",
  default: []
});
const b = selector({
  key: "b",
  get: ({ get }) => {
    const list = get(a);
    return Math.random() > 0.5 ? list.slice(0, list.length / 2) : list;
  }
});
// 調(diào)用則區(qū)分useRecoilValue、useRecoilState
const list = useRecoilValue(b);
const [value, setValue] = useRecoilState(a);

zustand

然后到了勢頭挺猛的zustand,npm的下載量已經(jīng)能趕上MobX了。趨勢對比基本的調(diào)用真的挺簡潔的,通過create定義store,使用的時(shí)候直接調(diào)用就好。用起來比recoil方便多了。

但是呢zustand的狀態(tài)都是不可變,getState時(shí)跟redux一樣要用到很多擴(kuò)展運(yùn)算符。官方是推薦引入immer,但這樣寫法又變復(fù)雜了一點(diǎn)。

另外zustand定義store時(shí)顆粒度需要挺細(xì)的,不然組件重復(fù)渲染的問題不好解決。不像MobX那樣可以把同一個頁面的store寫到一個文件里,zustand拆分的維度是需要按組件渲染狀態(tài)去劃分。

如果能像React toolkit那樣不需要用戶自己引入immer的話zustand還是挺香的。因?yàn)楹笈_系統(tǒng)一般來說交互類的狀態(tài)并不多,拆分顆粒度過細(xì)的問題并不大。而要開發(fā)人員自己每次都手動增加immer還是挺煩的。
總結(jié):需要引入額外的庫,store拆分要求比較細(xì)。

// 定義store
import produce from 'immer';
// list這個值不拆出去的話,在組件A修改title的值會引起list所在組件B的渲染。
const useStore = create<TitleState>((set) => ({
  title: '',
  list: [],
  setTitle: (title) => set(produce((state: TitleState) => {
    state.title = title;
  })),
}));
// 組件A 使用title
const { title, setTitle } = useStore();
// 組件B 使用list
const { list } = useStore();

MobX

是的,說了一圈狀態(tài)管理庫最后還是選擇MobX。

MobX使用起來很簡單,主要用到useLocalStore跟useObserver兩個api。store可以按照頁面劃分,維護(hù)起來很方便。性能也好,按照store的值去拆分組件就行。

至于說React加MobX不如用vue的說法,可能從性能上說是這樣。但本質(zhì)上說選擇React主要是看重React衍生出來的其強(qiáng)大的生態(tài)環(huán)境,而不是其他原因。

舉一個典型例子就是React Native。如果有APP跨端開發(fā)需求的話,那么React Native還是比較熱門的解決方案。目前React從生態(tài)成熟度上來說有著其他框架都達(dá)不到的高度,前端團(tuán)隊(duì)可以用React這一個框架去解決web、app、服務(wù)端渲染等多個場景的開發(fā)需求。使用一個技術(shù)棧能夠降低開發(fā)成本,開發(fā)人員切換開發(fā)場景的成本比較低,不需要學(xué)額外的框架語法。

所以說沒必要跟其他框架攀比,既然選擇了React,那就在React體系內(nèi)找一個好用的狀態(tài)管理庫就行,不要有其他的心理負(fù)擔(dān)。

// 一個文件定義一個頁面的store
class ListStore {
    constructor() {
        makeAutoObservable(this);
    }
    title = '';
    list = [];
    setList(values) {
        this.list = values;
    }
}
// 使用
const localStore = useLocalStore(() => store);
useObserver(() => (
    <div>
      {localStore.list.map((item) => (<div key={item.id}>{item.name}</div>))}
    </div>
));

補(bǔ)充:關(guān)于React組件重復(fù)渲染問題,網(wǎng)上有些言論是覺得無所謂。

但如果不管的話當(dāng)項(xiàng)目隨著時(shí)間而變得復(fù)雜之后很可能會遇到性能問題,到時(shí)候想改難度就變大了。

即使花大力氣重構(gòu)之后也面臨測試問題,項(xiàng)目上線需要申請測試資源對業(yè)務(wù)功能進(jìn)行回歸測試,總得來說還是比較麻煩的。

而MobX處理組件重復(fù)渲染問題挺方便的,只要組件拆分得當(dāng)就不需要開發(fā)者過多關(guān)心。

三、hooks的使用問題與解決方案

技術(shù)棧選好之后接下來就是確定React代碼的開發(fā)形式了。
首先是目前在React項(xiàng)目中使用hooks的寫法是必須的,這是官方確定的路線。

問題但是用hooks會遇到兩個比較麻煩的問題,一個是useEffect、useCallback、useMemo這些API的依賴項(xiàng)過多時(shí)的問題。另一個是useEffect的使用問題。

依賴項(xiàng)問題:

先說依賴項(xiàng)問題,項(xiàng)目中遇到useEffect、useCallback、useMemo這些API最頭疼的是后面跟著好幾個依賴項(xiàng),當(dāng)你要去修改里面的功能時(shí)你必須查看每個依賴項(xiàng)的具體作用,了解它們的更新時(shí)期。新增加的狀態(tài)需要考慮是用useState還是用useRef,又或者是兩者并存。總之心智負(fù)擔(dān)還是挺高的。

// 需要查看每個依賴項(xiàng)的更新邏輯
const onChange = useCallback(() => {
    if (a) {
      setValue(b);
    }
}, [ a, b ]);

useEffect問題:

再來就是useEffect的使用問題,不管在項(xiàng)目里看到一個useEffect跟著多個依賴項(xiàng)還是多個useEffect跟著不同的依賴項(xiàng),都是很頭疼的事情。

當(dāng)你需要增加或者修改里面的代碼邏輯時(shí)你需要把代碼都理解一遍,然后再決定你新的代碼邏輯是寫在現(xiàn)有的useEffect里還是再新增一個useEffect去承接。

// 一個useEffect里有多個依賴項(xiàng)
useEffect(() => {}, [a, b, c])
// 多個useEffect跟著各自的依賴項(xiàng)
useEffect(() => {}, [a])
useEffect(() => {}, [b])
useEffect(() => {}, [c])

解決方案前面決定了mobx作為狀態(tài)管理庫,所以這兩個問題的解決方案就是盡量不要使用useState,服務(wù)端的接口請求使用ahooks去解決,剩下的交互狀態(tài)使用mobx處理。

依賴項(xiàng)多問題:
首先看依賴項(xiàng)過多的解決方案,當(dāng)使用mobx的狀態(tài)之后依賴項(xiàng)只需要寫store一個依賴就行(不寫也行),這個時(shí)候在useEffect、useCallback這些API里面獲取的都是store里最新的值,不需要擔(dān)心狀態(tài)更新問題。

// 只需要寫localStore一個依賴,里面的a、b值永遠(yuǎn)都是最新的
const onChange = useCallback(() => {
    if (localStore.a) {
      localStore.setValue(localStore.b);
    }
}, [ localStore ]);// 也可以用[]

useEffect的使用問題:

然后是useEffect的使用問題,解決方案就是不使用useEffect。

跟上面依賴項(xiàng)多的解決方式一樣,服務(wù)端的接口請求都使用ahooks去解決,然后組件渲染狀態(tài)采用mobx結(jié)合ahooks提供的其他hooks方法(ahooks文檔),基本上就用不到useEffect了。

如果有監(jiān)聽某個值然后渲染層級嵌套比較深的組件的需求,比如父組件某個狀態(tài)變更之后需要孫子組件的form表單執(zhí)行清空動作的場景,那這個時(shí)候可以使用MobX的reaction去處理。

// 當(dāng)狀態(tài)變更之后觸發(fā)
reaction(
    () => localStore.visible,
    visible => {
      if (visible) {
        formRef.current?.resetFields(); // 清空表單
      }
    }
);

補(bǔ)充:MobX組件復(fù)用問題可以參考官方文檔提供的寫法,通過傳入一個返回不同狀態(tài)值的函數(shù)去解決。

// 官方推薦寫法
const GenericNameDisplayer = observer(({ getName }) => <DisplayName name={getName()} />)
const MyComponent = ({ person, car }) => (
    <>
        <GenericNameDisplayer getName={() => person.name} />
        <GenericNameDisplayer getName={() => car.model} />
        <GenericNameDisplayer getName={() => car.manufacturer.name} />
    </>
)

總結(jié)

1、系統(tǒng)的技術(shù)棧是React、React-router、antd、ahooks跟MobX。

2、狀態(tài)管理庫選擇MobX可以兼顧開發(fā)效率、后期維護(hù)跟性能問題。

3、hooks問題的解決方案主要是用ahooks處理服務(wù)端狀態(tài),然后用MobX處理剩下的交互狀態(tài);盡量少使用useState,不使用useEffect。

4、后續(xù)會補(bǔ)充一個代碼模板,把一些常用的后臺系統(tǒng)頁面的具體代碼組織形式補(bǔ)充進(jìn)來。

5、最佳實(shí)踐的意義在于團(tuán)隊(duì)內(nèi)部統(tǒng)一一個代碼寫法,以此實(shí)現(xiàn)降低項(xiàng)目開發(fā)成本以及同事之間協(xié)作成本的目標(biāo)。因?yàn)榇a結(jié)構(gòu)的一致可以方便項(xiàng)目后期的維護(hù)。假設(shè)說React官方推出了一個新的代碼組織形式,那么一個結(jié)構(gòu)統(tǒng)一的項(xiàng)目就能夠快速遷移到新寫法上面(最理想情況是寫一個腳本批量把代碼進(jìn)行替換)。而且團(tuán)隊(duì)的開發(fā)人員也能快速理解不同項(xiàng)目的結(jié)構(gòu)跟功能,不會出現(xiàn)某個項(xiàng)目只有某個同事能開發(fā)的情況。

6、本文這個最佳實(shí)踐是根據(jù)自身團(tuán)隊(duì)情況設(shè)計(jì)的,如果也比較看中開發(fā)效率跟后期維護(hù)可以參考這個模式。

以上就是react后臺系統(tǒng)最佳實(shí)踐示例詳解的詳細(xì)內(nèi)容,更多關(guān)于react后臺系統(tǒng)實(shí)踐的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React學(xué)習(xí)之事件綁定的幾種方法對比

    React學(xué)習(xí)之事件綁定的幾種方法對比

    這篇文章主要給大家介紹了關(guān)于React學(xué)習(xí)之事件綁定的幾種方法對比,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • 在React中this容易遇到的問題詳解

    在React中this容易遇到的問題詳解

    這篇文章主要介紹了在React中this容易遇到的問題總結(jié),文中有詳細(xì)的示例代碼,希望對大家有一定的幫助,需要的朋友可以參考下
    2023-05-05
  • 前端 react 實(shí)現(xiàn)圖片上傳前壓縮(縮率圖)

    前端 react 實(shí)現(xiàn)圖片上傳前壓縮(縮率圖)

    這篇文章主要介紹了前端 react 實(shí)現(xiàn)圖片上傳前壓縮(縮率圖),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • 簡談創(chuàng)建React Component的幾種方式

    簡談創(chuàng)建React Component的幾種方式

    這篇文章主要介紹了創(chuàng)建React Component的幾種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • React-Router6版本的更新引起的路由用法變化

    React-Router6版本的更新引起的路由用法變化

    本文主要介紹了React-Router6版本的更新引起的路由用法變化,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 詳解react-router4 異步加載路由兩種方法

    詳解react-router4 異步加載路由兩種方法

    本篇文章主要介紹了詳解react-router4 異步加載路由兩種方法 ,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-09-09
  • React Hook - 自定義Hook的基本使用和案例講解

    React Hook - 自定義Hook的基本使用和案例講解

    自定義Hook本質(zhì)上只是一種函數(shù)代碼邏輯的抽取,嚴(yán)格意義上來說,它本身并不算React的特性,這篇文章主要介紹了React類組件和函數(shù)組件對比-Hooks的介紹及初體驗(yàn),需要的朋友可以參考下
    2022-11-11
  • 記React connect的幾種寫法(小結(jié))

    記React connect的幾種寫法(小結(jié))

    這篇文章主要介紹了記React connect的幾種寫法(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • react如何實(shí)現(xiàn)表格多條件搜索

    react如何實(shí)現(xiàn)表格多條件搜索

    這篇文章主要介紹了react如何實(shí)現(xiàn)表格多條件搜索問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React-Native做一個文本輸入框組件的實(shí)現(xiàn)代碼

    React-Native做一個文本輸入框組件的實(shí)現(xiàn)代碼

    這篇文章主要介紹了React-Native做一個文本輸入框組件的實(shí)現(xiàn)代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-08-08

最新評論