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

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

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

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

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

1. 要做什么

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

2. 要求

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

1、開(kāi)發(fā)效率。

2、可維護(hù)性。

3、性能。

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

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

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

下面詳細(xì)說(shuō)一下?tīng)顟B(tài)管理庫(kù)的選型過(guò)程。

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

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

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

context

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

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

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

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

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

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

redux

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

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

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

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

且對(duì)比其他狀態(tài)庫(kù)Redux Toolkit使用起來(lái)還是不夠簡(jiǎn)便。

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

// 代碼來(lái)源網(wǎng)上的[案例](https://codesandbox.io/s/react-ts-redux-toolkit-saga-knq31?file=/src/api/user/userSlice.ts:1752-1761)
// 這一坨代碼實(shí)現(xiàn)的功能隨便換個(gè)庫(kù)就只要幾行就搞定
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

官方還推薦了一個(gè)叫recoil的狀態(tài)管理庫(kù),使用了下感覺(jué)也不夠簡(jiǎn)便。

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

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

總結(jié):簡(jiǎn)便性被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

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

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

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

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

// 定義store
import produce from 'immer';
// list這個(gè)值不拆出去的話,在組件A修改title的值會(huì)引起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

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

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

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

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

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

// 一個(gè)文件定義一個(gè)頁(yè)面的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èn)題,網(wǎng)上有些言論是覺(jué)得無(wú)所謂。

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

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

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

三、hooks的使用問(wèn)題與解決方案

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

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

依賴項(xiàng)問(wèn)題:

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

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

useEffect問(wèn)題:

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

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

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

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

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

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

useEffect的使用問(wèn)題:

然后是useEffect的使用問(wèn)題,解決方案就是不使用useEffect。

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

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

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

補(bǔ)充:MobX組件復(fù)用問(wèn)題可以參考官方文檔提供的寫法,通過(guò)傳入一個(gè)返回不同狀態(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)管理庫(kù)選擇MobX可以兼顧開(kāi)發(fā)效率、后期維護(hù)跟性能問(wèn)題。

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

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

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

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

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

相關(guān)文章

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

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

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

    在React中this容易遇到的問(wèn)題詳解

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

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

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

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

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

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

    本文主要介紹了React-Router6版本的更新引起的路由用法變化,文中通過(guò)示例代碼介紹的非常詳細(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)格意義上來(lái)說(shuō),它本身并不算React的特性,這篇文章主要介紹了React類組件和函數(shù)組件對(duì)比-Hooks的介紹及初體驗(yàn),需要的朋友可以參考下
    2022-11-11
  • 記React connect的幾種寫法(小結(jié))

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

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

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

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

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

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

最新評(píng)論