主頁 > 企業開發 > React封裝強業務hook的一個例子

React封裝強業務hook的一個例子

2020-09-29 18:45:07 企業開發

最近因為使用串列展示的需求有點多,就想著把串列分頁篩選的邏輯抽象一下,看了umi的一個useTable的hook,也不能滿足業務需要,于是就自己寫了一個,支持本地分頁篩選和介面分頁篩選,

思路就是,篩選的欄位都使用form表單控制,然后在hook里面將form和table聯合起來,

  下面貼出原始碼




  1 import { TableProps, PaginationProps } from '@slardar/antd';
  2 import React, { useEffect } from 'react';
  3 import {
  4   PaginationConfig,
  5   SorterResult,
  6   TableCurrentDataSource
  7 } from 'antd/lib/table';
  8 import { useDeepCompareEffect } from '@byted-woody/slardar';
  9 
 10 export type WrappedFormUtils = any;
 11 
 12 export interface TableControlState<T> extends TableProps<DataRow> {
 13   pagination: PaginationProps;
 14   sorter?: SorterResult<DataRow>;
 15   loading?: boolean;
 16 }
 17 
 18 // 搜索引數描述
 19 export interface SearchDescribe {
 20   // 欄位名
 21   fieldName: string;
 22   iniValue?: any;
 23   // 輸入值決議,比如日期輸入決議
 24   decodeFn?: any;
 25   // 自定義搜索函式
 26   searchFn?: (record: DataRow, desc: SearchDescribe) => boolean;
 27   // 決議后的值
 28   searchValue?: any;
 29   // 呼叫介面或者只在本地過濾
 30   searchMod?: 'api' | 'local';
 31   // 搜索的欄位,默認只搜索當前欄位
 32   searchFields?: string[];
 33 }
 34 
 35 export interface DataReceive {
 36   pageSize?: number;
 37   pageIndex?: number;
 38   pageTotal?: number;
 39   pageData: any[];
 40 }
 41 
 42 export type DataRow = { [key: string]: any };
 43 export type DataApiGet = (
 44   apiParams,
 45   pagination?: { pageIndex?: number; pageSize?: number }
 46 ) => Promise<DataReceive>;
 47 
 48 export interface FormTableReq {
 49   form: WrappedFormUtils;
 50   getDataApi: DataApiGet;
 51   getDataParam?: { [key: string]: any };
 52   // 表單的欄位決議
 53   includeFormFields?: (SearchDescribe | string)[];
 54   // 本地分頁
 55   localPagination?: boolean;
 56   // 本地搜索
 57   localSearch?: boolean;
 58   // 本地分頁+搜索
 59   local?: boolean;
 60   afterFetchData?: (v: any) => void;
 61   validateParam?: (param: any) => boolean;
 62 }
 63 
 64 const defaultTableState: TableControlState<DataRow> = {
 65   pagination: { current: 1, total: 0, pageSize: 10 },
 66   dataSource: [],
 67   loading: true
 68 };
 69 
 70 export type FormTableRet = [
 71   TableControlState<DataRow>,
 72   { fetchData: () => void }
 73 ];
 74 
 75 export function useFormTable(options: FormTableReq): FormTableRet {
 76   if (options.local) {
 77     options?.includeFormFields?.forEach(d => (d.searchMod = 'local'));
 78     return useFormTableLocal(options);
 79   } else {
 80     return useFormTableDB(options);
 81   }
 82 }
 83 
 84 // 本地分頁篩選版本
 85 export function useFormTableLocal(options: FormTableReq): FormTableRet {
 86   let { form, getDataApi, includeFormFields } = options;
 87   let currentFormValue =https://www.cnblogs.com/wanqingying/p/ form.getFieldsValue();
 88   // 快取資料
 89   let cacheDataListRef = React.useRef<DataRow[]>([]);
 90   let [tableState, setTableState] = React.useState<TableControlState<DataRow>>(
 91     defaultTableState
 92   );
 93   let searchApiParam = {};
 94   let searchLocalParam: SearchDescribe[] = [];
 95   if (Array.isArray(includeFormFields)) {
 96     includeFormFields?.forEach(describe => {
 97       if (typeof describe === 'string') {
 98         let value =https://www.cnblogs.com/wanqingying/p/ currentFormValue[describe];
 99         searchApiParam[describe] = value;
100       } else {
101         let value =https://www.cnblogs.com/wanqingying/p/ currentFormValue[describe.fieldName];
102         if (describe.decodeFn) {
103           value =https://www.cnblogs.com/wanqingying/p/ describe.decodeFn(value);
104         }
105         if (describe.searchMod === 'api') {
106           searchApiParam[describe.fieldName] = value;
107         } else {
108           searchLocalParam.push(
109             Object.assign({ searchValue: value }, describe)
110           );
111         }
112       }
113     });
114   } else {
115     searchApiParam = currentFormValue;
116   }
117 
118   function getTableApiData() {
119     getDataApi(searchApiParam).then(data =https://www.cnblogs.com/wanqingying/p/> {
120       cacheDataListRef.current = data.pageData;
121       setTableState(prevState => {
122         return Object.assign({}, prevState, { dataSource: [] });
123       });
124     });
125   }
126 
127   useEffect(getTableApiData, []);
128 
129   let { data, total } = calculatePageData(
130     tableState,
131     cacheDataListRef.current,
132     searchLocalParam
133   );
134 
135   function onSorterChange(
136     _pagination: PaginationConfig,
137     _filters: Record<keyof DataRow, string[]>,
138     _sorter: SorterResult<DataRow>,
139     _extra: TableCurrentDataSource<DataRow>
140   ) {
141     setTableState(prevState => {
142       return Object.assign({}, prevState, { sorter: _sorter });
143     });
144   }
145 
146   let newPage: PaginationProps = {
147     total: total,
148     onChange: (page, pageSize) => {
149       setTableState(prevState => {
150         prevState.pagination.pageSize = pageSize;
151         prevState.pagination.current = page;
152         return Object.assign({}, prevState);
153       });
154     }
155   };
156 
157   let finalPagination: PaginationProps = Object.assign(
158     {},
159     tableState.pagination,
160     newPage
161   );
162 
163   return [
164     { pagination: finalPagination, dataSource: data, onChange: onSorterChange },
165     { fetchData: getTableApiData }
166   ];
167 }
168 
169 // 介面分頁篩選版本 待完善
170 export function useFormTableDB(options: FormTableReq): FormTableRet {
171   let { form, getDataApi, includeFormFields } = options;
172   let currentFormValue =https://www.cnblogs.com/wanqingying/p/ form.getFieldsValue();
173   let [state, setState] = React.useState<TableControlState<DataRow>>(
174     defaultTableState
175   );
176   let searchApiParam: { [key: string]: any } = {};
177   let onceRef = React.useRef(false);
178   // 計算介面引數
179   if (Array.isArray(includeFormFields)) {
180     includeFormFields?.forEach(describe => {
181       if (typeof describe === 'string') {
182         let value =https://www.cnblogs.com/wanqingying/p/ currentFormValue[describe];
183         searchApiParam[describe] = value;
184       } else {
185         let value =https://www.cnblogs.com/wanqingying/p/ currentFormValue[describe.fieldName];
186         if (!onceRef.current && describe.iniValue) {
187           value =https://www.cnblogs.com/wanqingying/p/ describe.iniValue;
188         }
189         if (describe.decodeFn) {
190           value =https://www.cnblogs.com/wanqingying/p/ describe.decodeFn(value);
191           Object.assign(searchApiParam, value);
192         } else {
193           searchApiParam[describe.fieldName] = value;
194         }
195       }
196     });
197   } else {
198     searchApiParam = currentFormValue;
199   }
200   Object.assign(searchApiParam, options.getDataParam);
201   const pageParam = {
202     pageIndex: state.pagination.current,
203     pageSize: state.pagination.pageSize
204   };
205 
206   function getTableApiData() {
207     if (options.validateParam && !options.validateParam(searchApiParam)) {
208       return;
209     }
210     setState(prevState => {
211       return Object.assign({}, prevState, {
212         loading: true
213       } as TableControlState<any>);
214     });
215     getDataApi(searchApiParam, pageParam).then(data =https://www.cnblogs.com/wanqingying/p/> {
216       const { pageData, pageTotal } = data;
217       onceRef.current = true;
218       setState(prevState => {
219         return Object.assign({}, prevState, {
220           dataSource: pageData,
221           pagination: {
222             current: pageParam.pageIndex,
223             total: pageTotal || 0,
224             pageSize: pageParam.pageSize
225           },
226           loading: false
227         } as TableControlState<any>);
228       });
229       // 將表單資料同步到query
230       if (options.afterFetchData) {
231         options.afterFetchData(currentFormValue);
232       }
233     });
234   }
235   useDeepCompareEffect(getTableApiData, [searchApiParam, pageParam]);
236 
237   function onSorterChange(
238     _pagination: PaginationConfig,
239     _filters: Record<keyof DataRow, string[]>,
240     _sorter: SorterResult<DataRow>,
241     _extra: TableCurrentDataSource<DataRow>
242   ) {
243     setState(prevState => {
244       return Object.assign({}, prevState, { sorter: _sorter });
245     });
246   }
247 
248   let finalPagination: PaginationProps = Object.assign(
249     {
250       total: state.pagination.total,
251       onChange: (page, pageSize) => {
252         setState(prevState => {
253           prevState.pagination.pageSize = pageSize;
254           prevState.pagination.current = page;
255           return Object.assign({}, prevState);
256         });
257       }
258     },
259     state.pagination
260   );
261   let dataSource = state.dataSource;
262   if (options.localPagination) {
263     let { data, total } = calculatePageData(state, state.dataSource as any, []);
264     finalPagination.total = total;
265     dataSource = data;
266   }
267 
268   return [
269     {
270       pagination: finalPagination,
271       dataSource: dataSource,
272       onChange: onSorterChange,
273       loading: state.loading
274     },
275     { fetchData: getTableApiData },
276     state
277   ] as any;
278 }
279 
280 // 排序,篩選,計算分頁資料
281 function calculatePageData(
282   state: TableControlState<DataRow>,
283   dataList: DataRow[],
284   param: SearchDescribe[]
285 ) {
286   let { pagination, sorter } = state;
287   let { current = 1, pageSize = 10 } = pagination;
288   let copyDataList = Array.from(dataList);
289   // 排序
290   if (sorter?.column) {
291     let order = sorter.order;
292     let sortField = sorter.columnKey;
293     copyDataList = copyDataList.sort((a, b) => {
294       if (order === 'ascend') {
295         return a[sortField] - b[sortField];
296       } else {
297         return b[sortField] - a[sortField];
298       }
299     });
300   }
301   // 篩選
302   if (Array.isArray(param) && param.length > 0) {
303     copyDataList = copyDataList.filter(function filter(v) {
304       return param.every(desc => {
305         let { fieldName, searchValue, searchFields, searchFn } = desc;
306         let fieldValue =https://www.cnblogs.com/wanqingying/p/ v[fieldName];
307         let searchString = searchValue;
308         if (!searchString) {
309           return true;
310         }
311         if (searchFn) {
312           return searchFn(v, desc);
313         }
314         if (
315           typeof fieldValue !== 'string' ||
316           typeof searchString !== 'string'
317         ) {
318           return true;
319         }
320         if (searchFields?.length) {
321           return searchFields?.some(fieldName => {
322             let value =https://www.cnblogs.com/wanqingying/p/ v[fieldName];
323             if (typeof value =https://www.cnblogs.com/wanqingying/p/=='string') {
324               value.includes(searchString);
325             }
326             return false;
327           });
328         } else {
329           return fieldValue.includes(searchString);
330         }
331       });
332     });
333   }
334   // 分頁
335   let displayData =https://www.cnblogs.com/wanqingying/p/ copyDataList.slice(
336     (current - 1) * pageSize,
337     current * pageSize
338   );
339   // 默認空資料的展示
340   displayData.forEach(d => {
341     Object.entries(d).forEach(([k, v]) => {
342       if (v !== 0 && !v) {
343         d[k] = '---';
344       }
345     });
346     return d;
347   });
348   return { data: displayData, total: copyDataList.length };
349 }
useFormTable.tsx
下面是業務代碼demo
 1 import React, { FC } from 'react';
 2 import { Form, FormComponentProps, Input, Table } from '@slardar/antd';
 3 import { useFormTable } from '@slardar/common-modules';
 4 
 5 const FormItem = Form.Item;
 6 
 7 interface IProps extends FormComponentProps {}
 8 const DemoComponent: FC<IProps> = function(props) {
 9   const form = props.form;
10   let [tableState] = useFormTable({
11     form: props.form,
12     getDataApi: () => Promise.resolve([] as any),
13     includeFormFields: ['name', 'search']
14   });
15 
16   return (
17     <div className={'alarm-page-content'}>
18       <Form layout={'inline'}>
19         <FormItem>
20           {form.getFieldDecorator('name')(
21             <Input.Search
22               style={{ marginLeft: 16, width: 150 }}
23               placeholder="名稱"
24             />
25           )}
26         </FormItem>
27         <FormItem>
28           {form.getFieldDecorator('search')(
29             <Input.Search
30               style={{ marginLeft: 16, width: 150 }}
31               placeholder="評論"
32             />
33           )}
34         </FormItem>
35       </Form>
36       <Table {...tableState} columns={[]} />
37     </div>
38   );
39 };
40 
41 export const Demo = Form.create()(DemoComponent);
Demo.tsx
 1  1 import { useRef, useEffect } from 'react';
 2  2 import _ from 'lodash';
 3  3 export function useDeepCompareEffect<T>(fn, deps: T) {
 4  4   // 使用一個數字信號控制是否渲染,簡化 react 的計算,也便于除錯
 5  5   let renderRef = useRef<number | any>(0);
 6  6   let depsRef = useRef<T>(deps);
 7  7   if (!_.isEqual(deps, depsRef.current)) {
 8  8     renderRef.current++;
 9  9   }
10 10   depsRef.current = deps;
11 11   return useEffect(fn, [renderRef.current]);
12 12 }
useDeepCompareEffect.ts

 

 

 

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

標籤:JavaScript

上一篇:給webstorm換個背景圖

下一篇:React常用hook的優化useEffect淺比較

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(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
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more