最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React項(xiàng)目中hook實(shí)現(xiàn)展示對(duì)話框功能

 更新時(shí)間:2022年05月12日 11:24:44   作者:不喝牛奶的里昂  
Modal(模態(tài)框)是 web 開發(fā)中十分常見的組件,即從頁(yè)面中彈出的對(duì)話框,下面這篇文章主要給大家介紹了關(guān)于React項(xiàng)目中hook實(shí)現(xiàn)展示對(duì)話框功能的相關(guān)資料,需要的朋友可以參考下

React中使用對(duì)話框并不容易,主要因?yàn)椋?/p>

  1. 對(duì)話框需要在父組件中聲明,才能在子組件中控制其是否顯示
  2. 給對(duì)話框傳遞參數(shù)只能由props傳入,這意味著所有狀態(tài)管理都必須在更高階的組件中。而實(shí)際上這個(gè)對(duì)話框的參數(shù)只在子組件中才會(huì)維護(hù)。這時(shí)就需要我們使用自定義事件將參數(shù)傳回

這些問(wèn)題的本質(zhì)就是:如何用一個(gè)統(tǒng)一的方式去管理對(duì)話框,從而讓對(duì)話框相關(guān)的業(yè)務(wù)邏輯更加模塊化,以及和其他業(yè)務(wù)邏輯進(jìn)行解耦。

下面的方式只是經(jīng)驗(yàn)總結(jié),并不是唯一或者最佳實(shí)現(xiàn):

思路:使用全局狀態(tài)管理所有對(duì)話框

對(duì)話框本質(zhì)上是獨(dú)立于其他界面的一個(gè)窗口,用于完成一個(gè)獨(dú)立的功能。

所以,定義一個(gè)對(duì)話框,定位等價(jià)于定義一個(gè)具有唯一URL路徑的頁(yè)面。只是前者由彈出層實(shí)現(xiàn),后者是頁(yè)面的切換。

對(duì)話框UI彈出過(guò)程和頁(yè)面URL的切換非常類似,那么我們就可以給每一個(gè)對(duì)話框定義一個(gè)全局唯一的ID,然后通過(guò)這個(gè)ID去顯示或者隱藏一個(gè)對(duì)話框,并且給它傳遞參數(shù)。

嘗試設(shè)計(jì)一個(gè)API去做對(duì)話框的全局管理

假設(shè)我們實(shí)現(xiàn)的對(duì)話框?yàn)镹iceModal,那么我們的目標(biāo)是如下去使用:

const UserInfoModal = NiceModal.create(
    'user-info-modal',
    RealUserInfoModal
)
 
// 創(chuàng)建一個(gè)useNiceModal 這樣的hook去獲取某個(gè)id的對(duì)話框的操作對(duì)象
const modal = useNiceModal('user-info-modal')
 
// 通過(guò) modal.show 顯示一個(gè)對(duì)話框,并能夠給它傳遞參數(shù)
modal.show(args)
modal.hide()

可以看到,如果有這樣的API,那么無(wú)論在哪個(gè)層級(jí)的組件,只要知道某個(gè)Modal的ID,那么就都可以統(tǒng)一使用這些對(duì)話框,而不再需要考慮該在哪個(gè)層級(jí)的組件去定義了。

實(shí)現(xiàn):創(chuàng)建NiceModal組件和相關(guān)API

創(chuàng)建一個(gè)處理所有對(duì)話框的action creator 和 reducer

function showModal(modalId, args) {
    return {
        type: "nice-modal/show",
        payload: {
            modalId,
            args
        }
    }
}
 
function hideModal(modalId, force) {
    return {
        type: "nice-modal/hide",
        payload: {
            modalId,
            force
        }
    }
}
const modalReducer = (state = { hiding: {} }, action) {
    switch (action.type) {
        case "nice-modal/show":
            const {modalId, args} = action.payload
            return {
                ...state,
                // 如果存在 modalId 對(duì)應(yīng)的狀態(tài)(即args),就顯示這個(gè)對(duì)話框
                // 只要有參數(shù)就認(rèn)為對(duì)話框應(yīng)該顯示,如果沒(méi)有傳遞args,在reducer中使用默認(rèn)值true
                [modalId]: args || true,
                // 定義一個(gè)hiding 狀態(tài), 用于處理對(duì)話框關(guān)閉動(dòng)畫
                hiding: {
                    ...state.hiding,
                    [modalId]: false,
                }
            }
        case "nice-modal/hide":
            const { modalId, force: boolean } = action.payload
            // 只有force時(shí)才真正移除對(duì)話框,否則就是隱藏中hiding
            return action.payload.force 
                ? {
                    ...state,
                    [modalId]: false,
                    hiding: { [modalId]: false }
                  }
                : { ...state, hiding: { [modalId]: true } }
            default:
                return state
    }
}

這段代碼的主要思路就是通過(guò)Redux的store去存儲(chǔ)每個(gè)對(duì)話框狀態(tài)和參數(shù)。在這里設(shè)計(jì)了兩個(gè)action,分別顯示和隱藏對(duì)話框。

特別注意的是,這里加入了hiding這樣的一個(gè)狀態(tài),用來(lái)處理對(duì)話框關(guān)閉過(guò)程動(dòng)畫。

根據(jù)使用順序,首先實(shí)現(xiàn) createNiceModal,

使用容器模式,在對(duì)話框不可見時(shí)直接返回null,從而不渲染任何內(nèi)容,

確保即使頁(yè)面上定義了100個(gè)對(duì)話框,也不會(huì)影響性能。

createNiceModal = (modalId, Comp) => {
    return (props) => {
        const { visible, args } = useNiceModal(modalId)
        if (!visible) return null
        return <Comp {...args} {...props} />
    }
}
 
// 使用
const MyModal = createNiceModal('my-modal', () => {
    return (
        <NiceModal id="my-modal" title="Nice modal">
            Hello NiceModal
        </NiceModal>
    )
})

實(shí)現(xiàn)useNiceModal,根據(jù)id,封裝一些邏輯。

讓Redux的action使用起來(lái)更方便,在其內(nèi)部封裝對(duì)store的操作,從而實(shí)現(xiàn)對(duì)話框狀態(tài)管理的邏輯重用。

const modalCallbacks = {}
 
const useNiceModal = (modalId) => {
    const dispatch = useDispatch()
 
    // 封裝Redux action 用于顯示對(duì)話框
    const show = useCallback(
        (args) => {
            dispatch(showModal(modalId, args))
        },
        [dispatch, modalId]
    )
    
    // 封裝Redux action 用于隱藏對(duì)話框 (force: boolean)
    const hide = useCallback(
        (force) => {
            dispatch(hideModal(modalId, force))
        },
        [dispatch, modalId]
    )
 
    const args = useSelector((s) => s[modalId])
    const hiding = useSelector((s) => s.hiding[modalId])
 
    // 只要有參數(shù)就認(rèn)為對(duì)話框應(yīng)該顯示,如果沒(méi)有傳遞args,在reducer中使用默認(rèn)值true
    return { args, hiding, visible: !!args, show, hide }
}

這樣,我們就實(shí)現(xiàn)了一個(gè)NiceModal這樣的全局對(duì)話管理框架。

這樣使用:

import { Button } from 'antd'
import NiceModal, {
    createNiceModal,
    useNiceModal
} from "./NiceModal"
 
const MyModal = createNiceModal("my-modal", () => {
    return (
        <NiceModal id="my-modal" title="Nice Modal">
            Hello World
        </NiceModal>
    )
})
 
function MyModalExample() {
    const modal = useNiceModal("my-modal")
    return (
        <>
            <Button type="primary" onClick={() => modal.show()}>
                Show my modal
            </Button>
            <MyModal />
        </>
    )
}

處理對(duì)話框的返回值

如果說(shuō)對(duì)話框和頁(yè)面這兩種UI模式基本上是一致的,都是獨(dú)立窗口完成獨(dú)立邏輯。但是在用戶交互上,有一定的差別:

  • 對(duì)話框可能需要返回值給調(diào)用者
  • 而頁(yè)面切換一般不會(huì)關(guān)心頁(yè)面執(zhí)行的結(jié)果是什么

基于上面的NiceModal實(shí)現(xiàn)邏輯,現(xiàn)在考慮如何讓調(diào)用者獲得返回值。

我們可以把用戶在對(duì)話框中的操作看成一個(gè)異步操作邏輯,那么用戶在完成對(duì)話框中內(nèi)容的操作后,就認(rèn)為異步操作邏輯完成了。因此我們可以利用Promise來(lái)完成這樣的邏輯。

那么,我們要實(shí)現(xiàn)的API如下:

const modal = useNiceModal('my-modal')
// 實(shí)現(xiàn)一個(gè) promise API 來(lái)處理返回值
modal.show(args).then(res => {})

事實(shí)上,要實(shí)現(xiàn)這樣一個(gè)機(jī)制并不困難,就是在 useNiceModal 這個(gè) Hook 的實(shí)現(xiàn)中提供一個(gè) modal.resolve 這樣的方法,能夠去 resolve modal.show 返回的 Promise。

代碼的核心思路就是將show 和 resolve 兩個(gè)函數(shù)通過(guò) Promise 聯(lián)系起來(lái)。因此兩個(gè)函數(shù)調(diào)用位置不一樣,所以我們使用一個(gè)局部的臨時(shí)變量,來(lái)存放resolve回調(diào)函數(shù)。

// 使用一個(gè) object 緩存 promise 的 resolve 回調(diào)函數(shù)
const modalCallbacks = {};
export const useNiceModal = (modalId) => {
  const dispatch = useDispatch();
  const show = useCallback(
    (args) => {
      return new Promise((resolve) => {
        // 顯示對(duì)話框時(shí),返回 promise 并且將 resolve 方法臨時(shí)存起來(lái)
        modalCallbacks[modalId] = resolve;
        dispatch(showModal(modalId, args));
      });
    },
    [dispatch, modalId],
  );
  const resolve = useCallback(
    (args) => {
      if (modalCallbacks[modalId]) {
        // 如果存在 resolve 回調(diào)函數(shù),那么就調(diào)用
        modalCallbacks[modalId](args);
        // 確保只能 resolve 一次
        delete modalCallbacks[modalId];
      }
    },
    [modalId],
  );
  
  // 其它邏輯...
 
  // 將 resolve 也作為返回值的一部分
  return { show, hide, resolve, visible, hiding };
};

總結(jié)

到此這篇關(guān)于React項(xiàng)目中hook實(shí)現(xiàn)展示對(duì)話框功能的文章就介紹到這了,更多相關(guān)React hook展示對(duì)話框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React.memo函數(shù)中的參數(shù)示例詳解

    React.memo函數(shù)中的參數(shù)示例詳解

    這篇文章主要為大家介紹了React.memo函數(shù)中的參數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解React中setState回調(diào)函數(shù)

    詳解React中setState回調(diào)函數(shù)

    這篇文章主要介紹了詳解React中setState回調(diào)函數(shù),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • React使用UI(Ant?Design)框架的詳細(xì)過(guò)程

    React使用UI(Ant?Design)框架的詳細(xì)過(guò)程

    Ant?Design主要用于中后臺(tái)系統(tǒng)的使用,它提供了豐富的組件和工具,可以幫助開發(fā)人員快速構(gòu)建出美觀、易用的界面,同時(shí),Ant?Design還提供了詳細(xì)的文檔和示例,方便開發(fā)者學(xué)習(xí)和使用,這篇文章主要介紹了React使用UI(Ant?Design)框架,需要的朋友可以參考下
    2023-12-12
  • React Native之ListView實(shí)現(xiàn)九宮格效果的示例

    React Native之ListView實(shí)現(xiàn)九宮格效果的示例

    本篇文章主要介紹了React Native之ListView實(shí)現(xiàn)九宮格效果的示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 詳解React Fiber的工作原理

    詳解React Fiber的工作原理

    這篇文章主要介紹了React Fiber的工作原理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用React框架,感興趣的朋友可以了解下
    2021-04-04
  • react ant design樣式覆蓋問(wèn)題

    react ant design樣式覆蓋問(wèn)題

    這篇文章主要介紹了react ant design樣式覆蓋問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 詳解React的組件通訊

    詳解React的組件通訊

    這篇文章主要介紹了詳解react組件通訊方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • React如何優(yōu)雅的捕獲異常

    React如何優(yōu)雅的捕獲異常

    捕獲異常是來(lái)定位你錯(cuò)誤代碼的。本文主要介紹了 React如何捕獲異常,你知道多少種方法,ErrorBoundary,ErrorBoundary-try-catch等等。本文就來(lái)詳細(xì)的介紹一下
    2021-06-06
  • React?component.forceUpdate()強(qiáng)制重新渲染方式

    React?component.forceUpdate()強(qiáng)制重新渲染方式

    這篇文章主要介紹了React?component.forceUpdate()強(qiáng)制重新渲染方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • react中涉及的增加,刪除list方式

    react中涉及的增加,刪除list方式

    這篇文章主要介紹了react中涉及的增加,刪除list方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評(píng)論

苍山县| 萨嘎县| 姜堰市| 铁力市| 天柱县| 措勤县| 孟村| 宝山区| 麦盖提县| 涟水县| 石楼县| 察哈| 楚雄市| 中超| 朝阳市| 高邮市| 孟连| 岢岚县| 乌鲁木齐县| 渭南市| 桐柏县| 沁阳市| 许昌市| 镇宁| 山西省| 东城区| 遵义县| 澄江县| 安顺市| 沛县| 正安县| 鞍山市| 通辽市| 大关县| 广德县| 姚安县| 缙云县| 尼勒克县| 桓台县| 左云县| 临江市|