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

React彈窗使用方式NiceModal重新思考

 更新時(shí)間:2022年08月12日 10:49:38   作者:海秋  
這篇文章主要為大家介紹了React彈窗使用方式NiceModal重新思考分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一些有趣的真實(shí)場(chǎng)景

在開(kāi)始進(jìn)入正題之前,先看看一些與彈窗有關(guān)的有趣場(chǎng)景 ??。

案例一:全局彈窗

上圖是掘金的登錄彈窗,未登錄狀態(tài)下觸發(fā)該彈窗展示的時(shí)機(jī)有很多,比如:

  • 點(diǎn)擊 Header 上的登錄按鈕
  • 文章列表頁(yè)或詳情頁(yè)點(diǎn)贊以及評(píng)論文章
  • 發(fā)沸點(diǎn)、評(píng)論沸點(diǎn)以及點(diǎn)贊沸點(diǎn)
  • ...

開(kāi)發(fā)者往往會(huì)基于第三方組件庫(kù)定義一個(gè) <LoginModal />,然后將其掛載至 Root 組件下:

function App() {
  const [visible, setVisible] = useState(false);
  const [otherLoginData, setOtherLoginData] = useState();
  // other logic ...
  return (
    <div className="app">
      <Main />
      <LoginModal
        visible={visible}
        onCancel={() => setVisible(false)}
        otherLoginData={otherLoginData}
      />
    </div>
  );
}

這樣會(huì)帶來(lái)一些問(wèn)題:

  • <LoginModal /> 內(nèi)部邏輯在組件渲染的時(shí)候就會(huì)執(zhí)行,即使彈窗處于隱藏狀態(tài)
  • 額外的復(fù)雜度。由于存在多個(gè)觸發(fā)時(shí)機(jī),需要將 setVisible 以及 setOtherLoginData 透?jìng)髦?<Main /> 內(nèi)部的多個(gè)子組件,你可以選擇通過(guò) props 一層一層的傳遞進(jìn)去(鬼知道有多少層?。部梢砸牍ぞ哌M(jìn)行狀態(tài)共享,但不論怎樣,這都不是一件容易的事;
  • 隨著類(lèi)似的彈窗越來(lái)越多,根組件會(huì)維護(hù)很多彈窗組件的狀態(tài)...天知道為什么展示一個(gè)彈窗需要在多個(gè)文件里反復(fù)橫跳。

展示一個(gè)彈窗,為什么會(huì)變得如此復(fù)雜?

以上案例來(lái)自 @ebay/nice-modal-react,稍作修改

除了上述全局彈窗的場(chǎng)景,還有一種場(chǎng)景也很讓人頭疼。

案例二:存在分支以及依賴(lài)關(guān)系的彈窗

彈窗 1 確認(rèn)彈出彈窗 2,取消則彈出彈窗 3,彈窗 2 以及 彈窗 3 也存在對(duì)應(yīng)的分支邏輯,子孫滿堂輕而易舉,若按照常規(guī)聲明式彈窗組件的實(shí)現(xiàn),非??植溃?/p>

不那么通用的解決方案

擺脫所謂的 React 哲學(xué):數(shù)據(jù)驅(qū)動(dòng)視圖(view = f(data)),回歸原始的 window.confirm 以及 window.alert,很多問(wèn)題迎刃而解:

let mountNode: HTMLDivElement | null = null;
LoginModal.show = (props?: LoginModalProps) => {
  if (!mountNode) {
    mountNode = document.createElement('div');
    document.body.appendChild(mountNode);
  }
  // 通過(guò) ReactDOM.render 將組件渲染到固定的節(jié)點(diǎn)
  ReactDOM.render(<LoginModal {...props} visible />, mountNode);
};
LoginModal.hide = () => {
  mountNode && ReactDOM.render(<LoginModal {...props} visible={false} />, mountNode);
};
LoginModal.destroy = () => {
  // 通過(guò) ReactDOM.unmountComponentAtNode 卸載節(jié)點(diǎn)
  mountNode && ReactDOM.unmountComponentAtNode(mountNode);
};

經(jīng)過(guò)以上代碼處理,可以直接通過(guò) LoginModal.show({otherLoginData}) 展示彈窗(hide 以及 destroy 同理)。

對(duì)于存在依賴(lài)關(guān)系的彈窗,則可以通過(guò)返回 Promise 進(jìn)行鏈?zhǔn)秸{(diào)用,使用方式如下,此處不過(guò)多展開(kāi)。

try {
  const ret = await LoginModal.show({ otherLoginData });
  const ret = await Ohter1Modal.show();
} catch (error) {
  const ret = await Other2Modal.show();
}

由于該方案是通過(guò) ReactDOM.render 將組件渲染到一個(gè)新節(jié)點(diǎn),脫離了原始的 React 上下文,在某些強(qiáng)依賴(lài) Context 的場(chǎng)景會(huì)顯得有些麻煩。

可能是最好的彈窗實(shí)踐

某天在逛 github 的時(shí)候發(fā)現(xiàn)了 @ebay/nice-modal-react ,讓我們看看 ebay 的開(kāi)發(fā)者是如何讓彈窗在 React 下變得足夠 Nice。

創(chuàng)建彈窗

import { Modal } from 'antd';
import NiceModal, { useModal } from '@ebay/nice-modal-react';
export default NiceModal.create(({ name }) => {
  // Use a hook to manage the modal state
  const modal = useModal();
  return (
    <Modal
      title="Hello Antd"
      onOk={() => modal.hide()}
      visible={modal.visible}
      onCancel={() => modal.hide()}
      afterClose={() => modal.remove()}
    >
      Hello {name}!
    </Modal>
  );
});

和原先基于 antd 自定義一個(gè)彈窗組件非常相似,只不過(guò)彈窗顯隱相關(guān)的 props(如 visible/hide/remove) 是通過(guò) useModal 獲取,最外層則通過(guò) NiceModal.create 將組件進(jìn)行一層封裝(高階組件)。

使用彈窗

在使用彈窗之前,需要在Root 節(jié)點(diǎn)引入 <NiceModal.Provider />

import NiceModal from '@ebay/nice-modal-react';
ReactDOM.render(
  <React.StrictMode>
    <NiceModal.Provider>
      <App />
    </NiceModal.Provider>
  </React.StrictMode>,
  document.getElementById('root'),
);

隨后便可在任意地方通過(guò) NiceModal.show 展示先前自定義的彈窗:

import NiceModal from '@ebay/nice-modal-react';
import MyAntdModal from './my-antd-modal'; // created by above code
function App() {
  const showAntdModal = () => {
    // Show a modal with arguments passed to the component as props
    NiceModal.show(MyAntdModal, { name: 'Nate' })
  };
  return (
    <div className="app">
      <h1>Nice Modal Examples</h1>
      <div className="demo-buttons">
        <button onClick={showAntdModal}>Antd Modal</button>
      </div>
    </div>
  );
}

以上指引參考自 NiceModal 官方文檔

經(jīng)過(guò) NiceModal 的封裝,好處顯而易見(jiàn):

  • 調(diào)用過(guò)程干凈優(yōu)雅
  • 組件依舊存在于上下文中(可以自定義位置,默認(rèn)在 Provider 下)
  • show/hide 方法返回值為 Promise,方便鏈?zhǔn)秸{(diào)用(通過(guò)useModal().resolve(val)等方法改變 Promise 狀態(tài))

簡(jiǎn)單實(shí)現(xiàn)思路

如果你對(duì) NiceModal 的實(shí)現(xiàn)原理有興趣,那么可以思考一下我們之前的痛點(diǎn)是什么?案例一中描述了兩大主要痛點(diǎn):

  • 根組件渲染彈窗以及維護(hù)彈窗狀態(tài)過(guò)多 —— NiceModal.Provider 內(nèi)統(tǒng)一渲染彈窗
  • 顯隱相關(guān)狀態(tài)以及方法需要共享 —— 庫(kù)內(nèi)部維護(hù)對(duì)應(yīng)狀態(tài),通過(guò)統(tǒng)一 API (show/hide/useModal)暴露

案例二的鏈?zhǔn)秸{(diào)用在脫離聲明式組件后反而變得很容易,利用好 Promise 即可。

const Provider: React.FC = ({ children }) => {
  // 初始彈窗信息
  const [modals, _dispatch] = useReducer(reducer, initialState);
  dispatch = _dispatch;
  return (
    <NiceModalContext.Provider value={modals}>
      {children}
      <NiceModalPlaceholder />
    </NiceModalContext.Provider>
  );
};
const NiceModalPlaceholder: React.FC = () => {
  const modals = useContext(NiceModalContext);
  // 根據(jù)彈窗信息找到需要渲染的彈窗 ID (NiceModal.show 時(shí)更新)
  const visibleModalIds = Object.keys(modals).filter((id) =>
    Boolean(modals[id])
  );
  // 找到對(duì)應(yīng)創(chuàng)建的高階組件NiceModal.show 時(shí)注冊(cè)),注入 ID
  const toRender = visibleModalIds
    .filter((id) => MODAL_REGISTRY[id])
    .map((id) => ({
      id,
      ...MODAL_REGISTRY[id],
    }));
  return (
    <>
      {toRender.map((t) => (
        {/* 渲染 NiceModal.create 創(chuàng)建的高階組件 */}
        <t.comp key={t.id} id={t.id} />
      ))}
    </>
  );
};
const create =
  <P extends Record<string, unknown>>(
    Comp: React.ComponentType<P>
  ): React.FC<P & NiceModalHocProps> =>
  ({ id }) => {
    const modals = useContext(NiceModalContext);
    const shouldMount = Boolean(modals[id]);
    if (!shouldMount) {
      return null;
    }
    return (
      <NiceModalIdContext.Provider value={id}>
        {/* 找到對(duì)應(yīng) ID 的參數(shù),傳入內(nèi)部真實(shí)組件 */}
        <Comp {...(modals[id].args as P)} />
      </NiceModalIdContext.Provider>
    );
  };

理解上述三個(gè)方法后,show/hide/useModal 等方法就是基于 dispatch 函數(shù)進(jìn)行彈窗信息 Context 的更新從而觸發(fā)視圖更新(其中 show 方法多一步注冊(cè),生成 ID 并綁定至對(duì)應(yīng)的高階組件)。

推薦閱讀

以上就是React彈窗使用方式NiceModal重新思考的詳細(xì)內(nèi)容,更多關(guān)于React彈窗使用方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React Hook用法示例詳解(6個(gè)常見(jiàn)hook)

    React Hook用法示例詳解(6個(gè)常見(jiàn)hook)

    這篇文章主要介紹了React Hook用法詳解(6個(gè)常見(jiàn)hook),本文通過(guò)實(shí)例代碼給大家介紹了6個(gè)常見(jiàn)hook,需要的朋友可以參考下
    2021-04-04
  • React onClick/onChange傳參(bind綁定)問(wèn)題

    React onClick/onChange傳參(bind綁定)問(wèn)題

    這篇文章主要介紹了React onClick/onChange傳參(bind綁定)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • React+Koa實(shí)現(xiàn)文件上傳的示例

    React+Koa實(shí)現(xiàn)文件上傳的示例

    這篇文章主要介紹了React+Koa實(shí)現(xiàn)文件上傳的示例,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下
    2021-04-04
  • React?Hooks的useState、useRef使用小結(jié)

    React?Hooks的useState、useRef使用小結(jié)

    React Hooks 是 React 16.8 版本引入的新特性,useState和useRef是兩個(gè)常用的Hooks,本文主要介紹了React?Hooks的useState、useRef使用,感興趣的可以了解一下
    2024-01-01
  • react導(dǎo)出excel文件的四種方式

    react導(dǎo)出excel文件的四種方式

    本文主要介紹了react導(dǎo)出excel文件的四種方式,主要包括原生js導(dǎo)出,使用?js-export-excel,使用xlsx導(dǎo)出, 使用react-html-table-to-excel,感興趣的可以了解一下
    2023-11-11
  • React中的axios模塊及使用方法

    React中的axios模塊及使用方法

    axios 是一個(gè)基于 promise 的 HTTP 庫(kù),可以用在瀏覽器和 node.js 中,本文給大家分享React中axios模塊的使用方法,感興趣的朋友一起看看吧
    2022-03-03
  • react dva實(shí)現(xiàn)的代碼

    react dva實(shí)現(xiàn)的代碼

    dva是一個(gè)基于redux和redux-saga的數(shù)據(jù)流方案,然后為了簡(jiǎn)化開(kāi)發(fā)體驗(yàn),dva額外內(nèi)置了react-router,fetch,可以激烈為一個(gè)輕量級(jí)的應(yīng)用框架,這篇文章主要介紹了react dva實(shí)現(xiàn),需要的朋友可以參考下
    2021-11-11
  • React快速入門(mén)教程

    React快速入門(mén)教程

    本文主要介紹了React的相關(guān)知識(shí),具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • 解決React報(bào)錯(cuò)No duplicate props allowed

    解決React報(bào)錯(cuò)No duplicate props allowed

    這篇文章主要為大家介紹了React報(bào)錯(cuò)No duplicate props allowed解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React服務(wù)端渲染(總結(jié))

    React服務(wù)端渲染(總結(jié))

    當(dāng)我們要求渲染時(shí)間盡量快、頁(yè)面響應(yīng)速度快時(shí)就會(huì)用到服務(wù)端渲染,本篇文章主要介紹了React服務(wù)端渲染,有興趣的可以了解一下
    2017-07-07

最新評(píng)論