主頁 > 企業開發 > 基于分步表單的實踐探索

基于分步表單的實踐探索

2023-07-12 08:46:52 企業開發

我們是袋鼠云數堆疊 UED 團隊,致力于打造優秀的一站式資料中臺產品,我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值,,

本文作者:修能

以下內容充滿個人觀點,? ヽ(`Д′)? ┻━┻

前言

基于分布表單的需求,在中后臺管理中是一個非常常見的需求,通常具有如下布局:

file

其中,自定義需求度從高到低為,正文 > 按鈕區 > 步驟條,

雖然布局類似,但是實作的方式卻是天差地別,這里就探究一下究竟怎么樣實作可以兼具代碼的可維護性和可讀性呢?

指出問題

Container

我們這里,以「指標-資料模型」的代碼為例,

首先先來看看資料模型這里的代碼是如何實作的?

export default () => {
  ...
  return (
    <>
      <header>
        <Steps current={current}>
          {['tab1', 'tab2', 'tab3', 'tab4', 'tab5'].map(
      	     (title, index) => (
                <Step key={index} title={title} />
             )
          )}
        </Steps>
      </header>
      <Spin>
        {stepRender(current, {
           childRef,
           modelDetail,
           globalStep: globalStep.current,
           mode,
           isModelTypeDisabled,
           setModelDetail,
           setDisabled,
           onModelNameChange: handleModelNameChange,
        })}
        <Modal>...</Modal>
      </Spin>
      <footer>
        {current === EnumModifyStep.tab1 ? (
           <Button
             onClick={() => router.push('/url')}
           >
             取消
           </Button>
        ) : null}
        ...
      </footer>
    </>
  )
}

這是資料模型編輯頁面 Steps所在的容器組件的 DOM 部分的代碼,

可以看出來,設計者的思路是比較明確的,通過 header,content,和 footer 進行分層, 增加代碼的可讀性,

在 header 中,通過宣告 title 陣列的方式創建 Steps 的方式簡潔又不失可讀性,

在 content 中,有幾個問題的存在:

  1. 既然 header 和 footer 都有語意化的標簽強化可讀性,我認為這里其實也可以添加語意化的標簽強化可讀性,譬如 main或者section,當然同時還需要考慮會不會造成過深的層級,
  2. stepRender函式的實作把一大堆 params 傳到子組件是否合適,
  3. 為何 content 區域內,會存在 Modal?對于沒有設定 getPopupContainer 的 Modal 來說,其會通過 createPortal在 body 上創建,那么在這里不論是寫在 content 還是 header,都不會影響它的渲染,所以我推薦把 Modal 寫到最角落里,不影響可讀性,
  4. 在 footer 中,通過 current === 步驟 的方式去定義按鈕,我認為這種方式會使代碼顯得較為冗余,

Tab1

我們這里以指標相關代碼為例,以簡見深,以小見大

export default (props) => {
  ...
 const { cref, modelDetail, mode, onModelNameChange } = props;

  useImperativeHandle(cref, () => {
    return {
      validate: () => {...},
      getValue: () => {...},
    }
  });

   useEffect(() => {
     setFieldsValue({
       a: modelDetail.a,
       b: modelDetail.b,
       c: modelDetail.c,
     });
    }, [modelDetail]);

  return (
    <Form>
      <Row gutter={40}>
        <Col span={12}>
            ...
        </Col>
        <Col span={12}>
            ...
        </Col>
    </Row>
    <Row gutter={40}>
      <Col span={12}>
         ...
      </Col>
    </Row>
    </Form>
  )
}

這里我想指出的第一個問題是,ref 的使用,由于 ref 無法在 props 中傳遞,需要通過 forwardRef 才能拿到,然而這里通過 cref 這種比較 hack 的方式進行一個操作,我認為這是一個不推薦的做法,如果需要拿 ref 我建議是老老實實通過 forwardRef 拿,

其次是 Row 和 Col 的使用,并不是說 Col 達到 24 之后就需要再寫一個 Row,你可以繼續寫的呀,童鞋!

這里需要提出來的一個論點是,每一個子組件里去寫 Form 的方式好(即上面的這種寫法),還是總體寫一個 Form 的方式更好?個人認為前者存在的問題如下:

  1. 由于子組件寫 Form,但是提交(或下一步)按鈕在外面,那么必然需要用 ref 拿到子組件的實體,并呼叫相關方法,(上面是 validate 和 getValue 分別對應下一步和上一步呼叫)
  2. 沒有遵循 single source of truth(單一事實來源)
  3. 如果多層級結構,例如 RelationTableSelect 的話,每一層都有填寫內容,那么需要大量 Form + ref,降低可維護性,

除此之外,由于基礎資訊比較簡單,所以不存在 props 層層往下傳遞的問題,但是復雜組件就會存在層層往下傳遞的情況,那么就涉及到是否需要 context 的問題了,當然,我推薦是需要 context 的,

Tab2

這里再看一眼第二步關聯表的設計

interface ITab2Props {
  cref: IModifyRef;
  modelDetail?: Partial<IModelDetail>;
  mode: any;
  globalStep: number;
  updateModelDetail: Function;
  setDisabled?: Function;
}

const RelationTableSelect = (props: ITab2Props) => {}

首先,這里需要支持的一個設計思路是,通常情況下,切忌直接把 dispatch 傳遞給子組件

關聯表這里的設計由于層級嵌套很深,子組件非常多,導致updateModelDetail不斷往下傳遞,你完全不知道哪層組件在什么情況下會去修改這個值!!! 這對于 SSOT 來說,是毀滅性的打擊,

再加上 modelDetail 是一個很復雜的資料,對于可維護性來說,屬于是力中暴力地打擊了,

解決問題

綜上,我們設計分布表單的時候,需要規避以上的問題,遵循如下原則:

  1. SSOT
  2. 可維護性
  3. 可擴展性

首先實作如下組件:

<StepsForm
  current={current}
  onChange={setCurrent}
  titles={['tab1', 'tab2', 'tab3', 'tab4', 'tab5']}
/>

這一塊代碼比較簡單,無非就是投傳幾個值到對應的組件中去,

接下來考慮底部按鈕的可擴展性,

通過 submitter 屬性支持定制按鈕的互動屬性,

<StepsForm
  current={current}
  onChange={setCurrent}
  submitter={[
    {
      [StepsForm.PREV]: {
        children: '取消',
      },
    },
    null,
    {
      [PREVIEW]: {
        danger: true,
        children: '預覽',
      },
    },
  ]}
/>

接下來要解決按鈕的事件,這里有兩種方案,一種是將事件掛載在 Container 上(即這里的 StepsForm 組件),通過諸如 onCancel,onSubmit,onPrev等方式進行反饋,
我認為這種方式不夠好,原因有如下幾點

  1. 通常我們會把子組件提出來,不會和 Container 組件寫在一起,這就會使得我們需要在不同的組件中寫按鈕的互動邏輯和 UI 邏輯,存在隔離感
  2. 有時候我們需要把 Select.Option 相關的資料一起放到資料里給到服務端,這種方式互動需要把 Option 的資料提取到 Container 中
  3. 需要通過 ref 去子組件獲取值

而目前我考慮通過事件訂閱對按鈕事件觸發,通過 useEffect 監聽事件,但是這種方式的缺點如下:

  1. 不夠直觀,和我們通常來說的組件開發有一定相悖的思路

除了以上兩種方式以外,其實還有一種方式,即通過實作 Children 組件,將 Children 組件作為 StepsForm 的子組件,從而使得將每一步相關的 title 和 onSubmit 等方式都掛載在 Children 組件上,即 ant-design-pro 中的 StepsForm 的實作方式,我認為這種方式的優點在于直觀,不割裂,缺點在于如下:

  1. 為了獲取 title 不得不先渲染子組件,從而導致 DOM 先渲染出來,然后通過 active 判斷表單是否渲染,
  2. 導致子組件無法通過 useEffect獲取資料

其中第二點我認為是無法忍受的,這和開發組件的思路完全相悖,故摒棄這種方式
暫時考慮不清楚是第一種好還是第二種好,

這里先考慮實作第二種方式后組件書寫的效果:

export function () {
  ...
  StepsForm.useFooterEffect(
    ({ prev }) => {
      prev(() => {});
    },
    [StepsForm.PREV],
  );

  StepsForm.useFooterEffect(() => {
    message.info('預覽')
  }, [PREVIEW]);

  StepsForm.useFooterEffect(
    ({ next }) => {
      next(() => {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve();
          }, 1000);
        });
      });
    },
    [StepsForm.NEXT],
  );

  return (
    ...
  )
}

hook 的實作方式也比較簡單,基于事件訂閱,結合每一個按鈕都賦予一個唯一值,
實作按鈕互動觸發后,通過事件分發,觸發當前渲染的組件中的監聽 hook,

總結

本文意在探索分步表單的最佳實踐,防止不同的同學在開發該型別的需求會寫出五花八門的代碼,從而導致降低可維護性,

本文提到的解決方案也不認為是最佳實踐,其中不同的方法經過分析都存在優點和缺點,在實際的開發程序中,仍然需要根據具體的需求進行調整,

但是基于分步表單的特性和使用場景,總結出適用大部分情況下的方法論是有必要的,


最后

歡迎關注【袋鼠云數堆疊UED團隊】~
袋鼠云數堆疊UED團隊持續為廣大開發者分享技術成果,相繼參與開源了歡迎star

  • 大資料分布式任務調度系統——Taier
  • 輕量級的 Web IDE UI 框架——Molecule
  • 針對大資料領域的 SQL Parser 專案——dt-sql-parser
  • 袋鼠云數堆疊前端團隊代碼評審工程實踐檔案——code-review-practices
  • 一個速度更快、配置更靈活、使用更簡單的模塊打包器——ko

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/557055.html

標籤:其他

上一篇:js中字串的方法

下一篇:返回列表

標籤雲
其他(162415) Python(38274) JavaScript(25531) Java(18294) C(15239) 區塊鏈(8275) C#(7972) AI(7469) 爪哇(7425) MySQL(7294) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5876) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4615) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2438) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) HtmlCss(1998) .NET技术(1986) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1882) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 基于分步表單的實踐探索

    >我們是[袋鼠云數堆疊 UED 團隊](http://ued.dtstack.cn/),致力于打造優秀的一站式資料中臺產品。我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值。。 >本文作者:修能 ***以下內容充滿個人觀點。? ヽ(`Д´)? ┻━┻*** # 前言 基于分布表單的需求,在 ......

    uj5u.com 2023-07-12 08:46:52 more
  • js中字串的方法

    字串的17種方法。。。。。。 length:回傳字串的長度。 const str = "Hello, World!"; console.log(str.length); // 輸出 13 charAt(index):回傳指定索引位置的字符。 const str = "Hello, World!" ......

    uj5u.com 2023-07-12 08:46:38 more
  • 前端Vue仿美團地址管理組件串列組件 可用于電商平臺識訓地址管

    隨著技術的發展,開發的復雜度也越來越高,傳統開發方式將一個系統做成了整塊應用,經常出現的情況就是一個小小的改動或者一個小功能的增加可能會引起整體邏輯的修改,造成牽一發而動全身。 通過組件化開發,可以有效實作單獨開發,單獨維護,而且他們之間可以隨意的進行組合。大大提升開發效率低,降低維護成本。 組件化 ......

    uj5u.com 2023-07-12 08:46:17 more
  • 記錄--盤點前端實作檔案下載的幾種方式

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前端涉及到的檔案下載還是很多應用場景的,那么前端檔案下載有多少種方式呢?每種方式有什么優缺點呢?下面就來一一介紹。 1. 使用 a 標簽下載 通過a標簽的download屬性來實作檔案下載,這種方式是最簡單的,也是我們比較常用的方式,先來 ......

    uj5u.com 2023-07-12 08:46:10 more
  • 基于分步表單的實踐探索

    >我們是[袋鼠云數堆疊 UED 團隊](http://ued.dtstack.cn/),致力于打造優秀的一站式資料中臺產品。我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值。。 >本文作者:修能 ***以下內容充滿個人觀點。? ヽ(`Д´)? ┻━┻*** # 前言 基于分布表單的需求,在 ......

    uj5u.com 2023-07-12 08:40:55 more
  • SQ工具|10|ArcMap資料庫合并工具

    可對相同結構的資料庫進行批量合并,包括shp檔案 點擊目標資料庫選擇要'合并至'的資料庫,點擊+按鈕添加要參與合并的資料庫,選擇完所有需要合并的資料庫后,點擊確認即可完成合并。 備注: ①參與合并的資料庫結構必須相等。 ②目標資料庫建議選擇相同結構的空資料庫。 ③資料庫較多時,最好分批合并。字太少了 ......

    uj5u.com 2023-07-12 08:34:28 more
  • SQ工具|9|資料安全|ArcMap自動保存|ArcMap自動備份插件

    可解決在作業程序中停電、軟體閃退等一系列問題導致的ArcMap自動退出而未來得及保存資料造成的資料丟失的問題 一、自動保存 在開啟編輯的狀態下,設定保存周期,狀態選擇開啟點擊確認即可開啟自動保存任務(提示框位于右下角) 當一個保存周期內資料未變化時,將不會觸發自動保存。 狀態選擇關閉時點擊確認,即可 ......

    uj5u.com 2023-07-12 08:34:19 more
  • SQ工具|8|欄位順序編碼|同項順序編碼|自西向東,自北向南編碼

    順序編碼主要解決類似BSM等類欄位按照12345順序編碼以及同專案順序編碼。 一:順序編碼的實作 ①使用欄位計算器及OID欄位進行更新 例:如果想在index中填充從1開始依次加1的值,那么在欄位計算器中將index計算為FID+1即可,在源檔案為shp檔案時,OID一直保持從0開始遞增的值。但是在 ......

    uj5u.com 2023-07-12 08:34:04 more
  • SQ工具|7|域值型欄位的更新

    應用場景:如不動產登記系統中的ZDJBXX表,存在欄位YT和GHYTMC,兩欄位按照土地用途型別字典表一一對應,比如0702對應農村宅基地。根據YT更新GHYTMC。 已內置了四組字典,分別是土地用途,房屋用途,房屋性質,房屋型別 分別選擇對應的鍵欄位,值欄位;值欄位為要更新的欄位,若勾選下方選擇框 ......

    uj5u.com 2023-07-12 08:33:50 more
  • 4.10 x64dbg 反匯編功能的封裝

    LyScript 插件提供的反匯編系列函式雖然能夠實作基本的反匯編功能,但在實際使用中,可能會遇到一些更為復雜的需求,此時就需要根據自身需要進行二次開發,以實作更加高級的功能。本章將繼續深入探索反匯編功能,并將介紹如何實作反匯編代碼的檢索、獲取上下一條代碼等功能。這些功能對于分析和除錯代碼都非常有用... ......

    uj5u.com 2023-07-12 08:33:39 more