Umi+React+Xrender+Hsf項目開發總結

一、菜單路由配置

1.umirc.ts?中的路由配置

.umirc.ts 文件是 UmiJS 框架中的一個配置文件,用于配置應用的全局設置,包括但不限于路由、插件、樣式等。

import { defineConfig } from 'umi';
import config from './def/config';export default defineConfig({plugins: ['@umijs/plugins/dist/model', '@umijs/plugins/dist/request'],model: {},request: {},title: '客服管理后臺',publicPath: config.publicPath,favicons: [// 'https://domain.com/favicon.ico',//設置icon],esbuildMinifyIIFE: true,history: {type: 'hash',},routes: [{path: '/',component: '@/pages/business/index',},{path: '/public',component: '@/pages/publicInstance/index',layout: false,ignoreAuth: true,},{path: '/common',name: '通用',icon: 'menu',routes: [{path: '/common/business',name: '業務線管理',component: '@/pages/business/index',},{path: '/common/peopleManage',name: '人員管理配置',component: '@/pages/index',},{path: '/common/skills',name: '技能組管理配置',component: '@/pages/skills/index',},{path: '/common/dialogChange',name: '轉交配置',component: '@/pages/dialogChange/index',},],},// 其他路由配置...],
});
主要配置項解釋:
  1. defineConfig:

    • 這是一個從?umi?導入的函數,用來創建 Umi 配置對象。它幫助開發者更方便地編寫和組織配置。
  2. plugins:

    • 定義使用的插件列表。這里使用了兩個插件:@umijs/plugins/dist/model?和?@umijs/plugins/dist/request,它們分別用于狀態管理和請求處理。
  3. routes:

    • 定義應用的路由表,每個路由對象可以有以下屬性:
      • path: 路由路徑。
      • component: 對應路徑下加載的組件。
      • routes: 子路由數組,允許嵌套路由。
      • layout: 是否使用布局,默認是?true。當設置為?false?時,表示該路由下的頁面不使用全局布局。
      • ignoreAuth: 忽略權限驗證,對于無需登錄即可訪問的公共頁面非常有用。
示例分析:
  • 根路徑 /:

    • 當用戶訪問根路徑時,會加載?@/pages/business/index?組件。
  • 免登錄頁面 /public:

    • 訪問此路徑時,加載?@/pages/publicInstance/index?組件,且設置了?layout: false?和?ignoreAuth: true,意味著這個頁面不會使用全局布局,并且不需要進行權限驗證。
  • 通用模塊 /common:

    • 包含四個子路由,每個子路由都有自己的?pathname?和對應的?component。這些子路由都歸屬于“通用”分類下,通過?icon?屬性可以在側邊欄或導航中顯示相應的圖標。

2.menuConfig.ts?中的菜單項配置

menuConfig.ts 文件則通常用于定義側邊欄或頂部導航欄的菜單結構。

import React from 'react';
import {BuildOutlined,
} from '@ant-design/icons';
import { MenuProps } from 'antd';// 定義菜單項類型
export type MenuItem = NonNullable<MenuProps['items']>[number];
export const menuData: MenuItem[] = [{key: 'common',icon: React.createElement(BuildOutlined),label: '通用',children: [{key: '/common/business',label: '業務線管理',},// ...更多菜單項],},// ...更多菜單組
];

1.?MenuProps['items']

這是從 Ant Design 的 MenuProps 類型中取出 items 屬性的類型。

1.?NonNullable<...>

  • NonNullable<T>?是 TypeScript 內置的一個工具類型,用于從類型?T?中排除?null?和?undefined。換句話說,它將類型?T?中可能存在的?null?或?undefined?移除掉。

3.?[number]?

  • 從?(MenuItemType)[]?中提取出單個元素的類型,即?MenuItemType

二、hsf接口的調用

1、配置服務信息

import business from '@/pages/business';
import AccessProcess from '@/pages/entrance/accessProcess';
import { access } from 'fs';
import java from 'js-to-java';
import { request } from 'umi';export const isDaily = window.location.host.match(/localhost|.alibaba.net|-test.uc.alibaba-inc.com|30.211.81.4/,
);
export const version1 = isDaily ? '1.0.0.DAILY' : '1.0.0';
export const version2 = isDaily ? '2.0.1.DAILY' : '2.0.1';
export const version3 = isDaily ? '2.0.0.KF.DAILY' : '2.0.0.KF';// 固定的hsf服務信息
const servicer: any = {process: {appName: 'cs-xadmin',pathname: 'xxxx',version: isDaily ? '2.0.1.DAILY' : '2.0.1',},oldProcess: {appName: 'cs-xxflow',pathname: 'xxxx',version: isDaily ? '2.0.1.DAILY' : '2.0.1',},
};
/*** hsf通用調取方法* @param {string} key 對應服務key值(獲取pathname:version)* @param {string} className 類名* @param {string} action 方法名* @param {string} appName 應用名* @param {any} data 參數**/
export const hsfApi = async (key: string, { className, action, data }: any) => {// 如果是日常環境 & 路徑上帶有connectToLocalHsf參數,則調用本地hsf,把version中的DAILY 替換為 LOCALlet version = servicer[key]?.version;if (isDaily && window.location.hash.includes('connectHsf=local')) {version = servicer[key].version.replace('DAILY', 'LOCAL');}return request(`/api/hsf?action=${action}`, {method: 'POST',data: {pathname: `${servicer[key]?.pathname}:${version}`,action,appName: servicer[key].appName,data:data && className? [java(className, {...data,}),]: [],},});
};
pathname:
?appName:

2、封裝請求函數

// @ts-ignore
/* eslint-disable */
import { hsfApi } from '@/utils/api';/*** 分頁查詢技能組溢出規則* @param params 查詢參數*/
export async function pageList(params: {pageNo?: number;pageSize?: number;name?: string;fromSkillgroupId?: number;toSkillgroupId?: number;
}) {return hsfApi('onlineDispatch', {className: 'com.uc.cs.xadmin.client.param.dispatchschedule.PageOnlineDispatchScheduleParam',action: 'pageList',data: {...params,}});
className:?

action:?

?

參數解釋:
  • 'onlineDispatch'
    • 表示要調用的服務名,對應你在?api.ts?中配置的?servicer?對象里的鍵值。
    • 會去查找該服務的應用名、路徑、版本等信息。
  • className
    • 表示你這次請求的參數在后端對應的 Java 類型。
  • action: 'pageList'
    • 表示你要調用的方法名,即后端服務提供的某個接口方法。
  • data: { ...params }
    • 把傳入的?params?參數展開并傳入請求體中。
    • 最終會被包裝成一個 Java 對象發送到后端

三、頁面開發

1、父組件

(1)懶加載

import React from 'react';
const AddEditModal = React.lazy(() => import('./components/AddEditModal'));

?React.lazy 是 React 提供的一個用于實現代碼分割的功能。通過 React.lazy 和動態 import() 語法,你可以按需加載組件,而不是在應用初始化時就加載所有組件。

(2)useMemo

  const schema = useMemo(() => getOnlineDispatchSchema(groupValues), [groupValues]);

useMemo 是一個用于記憶化的 Hook,它接收兩個參數:

  1. 一個創建函數:該函數返回需要被記憶化的值。
  2. 一個依賴項數組:只有當這些依賴項發生變化時,才會重新計算記憶化的值;否則將返回之前記憶化的結果。
  const columns: any = useMemo(() => {   {title: '最后修改信息',dataIndex: 'modifyInfo', // 可以不綁定真實字段,僅占位width: 200,render: (_: any, record: any) => {const modifyTime = dayjs(record.modifyTime).format('YYYY-MM-DD HH:mm:ss');const modifier = record.modifier || '未知';return (<div style={{ lineHeight: 1.5 }}><div>{modifyTime}</div><div>{modifier}</div></div>);},},
}

(3)render

render: (_: any, record: any) => {}?的用法
  1. _:當前列的值。有時你可能不需要使用這個值,所以通常用下劃線 _ 來表示忽略這個參數。

  2. record:當前行的所有數據。這是一個對象,包含了該行所有字段的信息。

(4)請求緩存避免發起多個相同請求?

// 在組件外部創建緩存
const skillGroupsCache = {data: null as SkillGroup[] | null,promise: null as Promise<SkillGroup[] | null> | null // 允許Promise返回null
};const fetchSkillGroups = async () => {if (skillGroupsCache.data) return skillGroupsCache.data;if (skillGroupsCache.promise) return skillGroupsCache.promise;skillGroupsCache.promise = (async () => {try {const result = await index({/* 參數 */});skillGroupsCache.data = result.code === 200 ? result.data.rows?.map((v: SkillGroupResponse)  => ({ label: v.name, value: v.id })) || []: [];return skillGroupsCache.data;} catch (error) {console.error('獲取技能組失敗:', error);return [];} finally {skillGroupsCache.promise = null;}})();return skillGroupsCache.promise;
};
緩存對象?skillGroupsCache

  • data:用于存儲從服務器獲取到的技能組數據。如果已經成功獲取了數據,則直接使用緩存的數據,無需再次發起網絡請求。

  • promise:用于存儲正在進行中的異步請求,這樣可以確保在同一個數據獲取過程中,如果有多個地方同時請求相同的數據,它們將共享同一個請求結果,而不是各自發起新的請求。

  1. 檢查緩存數據

    • 首先檢查?skillGroupsCache.data?是否已經有值。如果有,說明之前已經成功獲取過數據,直接返回緩存的數據,避免重復請求。
  2. 檢查進行中的請求

    • 如果沒有緩存的數據,但?skillGroupsCache.promise?不為空,說明當前有一個正在進行中的請求。在這種情況下,直接返回這個正在進行中的請求(Promise),所有調用者將等待同一個請求的結果,而不是各自發起新的請求。
  3. 發起新請求

    • 如果既沒有緩存的數據也沒有正在進行中的請求,則創建一個新的異步請求來獲取數據,并將其存儲在?skillGroupsCache.promise?中。
    • 在請求成功后,將獲取到的數據存儲在?skillGroupsCache.data?中,并清空?skillGroupsCache.promise
    • 如果請求失敗,記錄錯誤信息并返回一個空數組。
  4. 清理

    • 無論請求成功還是失敗,在?finally?塊中都會將?skillGroupsCache.promise?設置為?null,以便后續的請求可以正常發起。

(5)初始化狀態鎖

 // 添加初始化狀態鎖const initializedRef = useRef(false);// 初始化數據useEffect(() => {console.log('initializedRef.current',initializedRef.current);if (initializedRef.current) return;initializedRef.current = true;const initData = async () => {setSpinning(true);try {setTableHeight(useInitTableHeight(-10));const [groups, pageData] = await Promise.all([fetchSkillGroups(),fetchPageList({ pageNo: 1, pageSize: 20 }) // 合并初始化請求]);setGroupValues(groups || []);setRawTableData(pageData.data.data.list || []);// setInitialized(true);} catch (error) {console.error('初始化失敗:', error);} finally {setSpinning(false);}};initData();
}, []);

通過 if (initializedRef.current) return; 來判斷是否已經執行過初始化操作。如果已經初始化則直接返回,不重復執行初始化邏輯。

使用?useRef?而不是?useState?的原因
  • useRefuseRef 返回一個可變的引用對象,其 .current 屬性在組件的整個生命周期內保持不變。修改 .current 屬性不會觸發組件的重新渲染

  • useState:每次調用 setState 函數都會導致組件重新渲染。如果我們使用 useState 來管理初始化狀態,那么每當更新該狀態時,都會導致組件重新渲染,這可能會引起性能問題或意外的行為。

(6)??和...運算符

  // 構造請求參數const payload: Record<string, any> = {pageNo: current ?? 1,pageSize: pageSize ?? 20,...(onlineDispatchName && { name: onlineDispatchName }),...(overflowSkillGroup && { fromSkillgroupId: overflowSkillGroup }),...(inflowSkillGroup && { toSkillgroupId: inflowSkillGroup }),...(modifier && { modifier }),};
??對比邏輯或運算符 (||)

在 ES2020 之前,開發者通常使用邏輯或運算符 (||) 來提供默認值。但是,|| 運算符會在左側操作數是任何假值(如 0, false, '' 等)時也返回右側的默認值

let current = 0;
console.log(current || 1); // 輸出: 1 (可能不符合預期)
console.log(current ?? 1); // 輸出: 0 (符合預期)

(7)枚舉列表轉換成對象

/*** 格式化enums* @param list - 所需要格式化的列表* list格式: [{value: "offline", desc: "下線"}, {value: "online", desc: "上線"}]* @returns 返回格式化后的enums {offline: "下線", online: "上線"}*/
const formatEnums = (list: any, label: string = 'desc', code: string = 'code') => {if (!list || list.length === 0) return null;return (list?.reduce((acc: any, cur: any) => {acc[cur[code]] = cur[label];return acc;}, {}) || null);
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82671.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82671.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82671.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【運維】基于Python打造分布式系統日志聚合與分析利器

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在分布式系統中,日志數據分散在多個節點,管理和分析變得復雜。本文詳細介紹如何基于Python開發一個日志聚合與分析工具,結合Logstash和F…

Python實戰:海量獲取京東商品信息

在數據驅動的商業時代&#xff0c;數據就是最寶貴的資源。對于電商從業者、市場分析師而言&#xff0c;從京東這類大型電商平臺獲取商品信息&#xff0c;能夠為市場調研、競品分析、銷售策略制定提供重要依據。今天&#xff0c;就來分享如何用Python實現京東商品信息的海量獲取…

聊一聊常見的超時問題:timeout

大家好&#xff0c;我是G探險者&#xff01; 在日常開發中&#xff0c;“超時&#xff08;Timeout&#xff09;”類錯誤是開發者們經常遇到的問題。無論是調用第三方服務、訪問數據庫&#xff0c;還是并發任務處理&#xff0c;都可能因超時而導致請求失敗或系統異常。 本文將系…

創建型模式:工廠方法(Factory Method)模式

一、簡介 工廠方法(Factory Method)模式是一種創建型設計模式,它定義了一個創建對象的接口,但讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。在 C# 中,工廠方法模式提供了一種更靈活的對象創建方式,將對象的創建和使用分離,提高了代碼的可維護性和…

外網訪問內網海康威視監控視頻的方案:WebRTC + Coturn 搭建

外網訪問內網海康威視監控視頻的方案&#xff1a;WebRTC Coturn 需求背景 在倉庫中有海康威視的監控攝像頭&#xff0c;內網中是可以直接訪問到監控攝像的畫面&#xff0c;由于項目的需求&#xff0c;需要在外網中也能看到監控畫面。 實現這個功能的意義在于遠程操控設備的…

Redis 8.0正式發布,再次開源為哪般?

Redis 8.0 已經于 2025 年 5 月 1 日正式發布&#xff0c;除了一些新功能和性能改進之外&#xff0c;一個非常重要的改變就是新增了開源的 AGPLv3 協議支持&#xff0c;再次回歸開源社區。 為什么說再次呢&#xff1f;這個需要從 2024 年 3 月份 Redis 7.4 說起&#xff0c;因為…

382_C++_在用戶會話結束時,檢查是否有其他會話仍然來自同一個客戶端 IP 地址,沒有連接狀態設置為斷開,否則為連接

之前出現的問題:重啟管理機,工作機上面熱備連接狀態顯示未連接 (此時是有一個工作機連接管理機的),所以正常應該是連接狀態解決:根因分析: 重啟管理機后,管理機給過來的cookie是空的,導致工作機同時存在兩個管理機的session,在其中一個超時后,調用回調函數通知會話斷開…

大模型系列(五)--- GPT3: Language Models are Few-Shot Learners

論文鏈接&#xff1a; Language Models are Few-Shot Learners 點評&#xff1a; GPT3把參數規模擴大到1750億&#xff0c;且在少樣本場景下性能優異。對于所有任務&#xff0c;GPT-3均未進行任何梯度更新或微調&#xff0c;僅通過純文本交互形式接收任務描述和少量示例。然而&…

【網絡分析工具】網絡工具wireshark、TCPdump、iperf使用詳解

這里寫目錄標題 1. wireshark1.1. 過濾包1.2. 常見分析 2. tcpdump3. iperf 1. wireshark **ip.dst eq 10.0.0.21** 是用于網絡流量分析工具&#xff08;例如 Wireshark 或 tcpdump&#xff09;的過濾器表達式。 它的作用是篩選出所有目標IP地址為 10.0.0.21 的數據包 IP.add…

Django rest_framework 信號機制生成并使用token

1、在setting.py 中增加設置 DEFAULT_AUTHENTICATION_CLASSES:[rest_framework.authentication.BasicAuthentication,#基本的用戶名密碼驗證rest_framework.authentication.SessionAuthentication,rest_framework.authentication.TokenAuthentication,# token 認證], INSTALLE…

SQL Server To Paimon Demo by Flink standalone cluster mode

需求&#xff1a;使用 Flink CDC 測試 SQL Server 連接 Paimon 操作&#xff1a;啟動 Flink standalone cluster 后&#xff0c;接著啟動 Flink SQL Client&#xff0c;則通過 Flink SQL Client 提交 insert & select job 到該 8081 cluster Flink SQL Client 執行案例 -…

MySQL 從入門到精通(四):備份與恢復實戰——從邏輯到物理,增量備份全解析

數據是企業的核心資產&#xff0c;而數據庫作為數據存儲的 “心臟”&#xff0c;其備份與恢復策略直接關系到業務的連續性。本文將結合 MySQL 的日志體系與備份工具&#xff0c;深入講解邏輯備份、物理備份、增量備份的實戰操作&#xff0c;幫助你構建可靠的數據庫保護方案。 目…

鴻蒙編譯boost整合linux跨平臺應用

openharmony deveco 4.1支持armeabi-v7a deveco 5.0后不支持arm32位系統 boost編譯 使用deveco的寫cmake集成boost boost使用1.88的最新版本&#xff0c;帶cmake工具鏈 https://github.com/boostorg/boost.git boost的源碼都在sub_module中 deveco 4.1的版本sdk最高到9&am…

機器視覺的平板電腦屏幕組件覆膜應用

在現代智能制造業中&#xff0c;平板電腦屏幕組件覆膜工序是確保產品外觀和功能完整性的重要環節。隨著技術的進步&#xff0c;傳統的覆膜方式已經無法滿足高速度、高精度的生產需求。而MasterAlign視覺系統的出現&#xff0c;將傳統覆膜工藝轉變為智能化、自動化的生產流程。在…

android-ndk開發(10): use of undeclared identifier ‘pthread_getname_np‘

1. 報錯描述 使用 pthread 獲取線程名字&#xff0c; 用到 pthread_getname_np 函數。 交叉編譯到 Android NDK 時鏈接報錯 test_pthread.cpp:19:5: error: use of undeclared identifier pthread_getname_np19 | pthread_getname_np(thread_id, thread_name, sizeof(thr…

【前端基礎】6、CSS的文本屬性(text相關)

目錄內容 text-decoration&#xff1a;設置文本裝飾線text-transform&#xff1a;文本中文字的大小寫轉換text-indent&#xff1a;首行縮進text-align&#xff1a;設置文本對齊方式 一、text-decoration&#xff1a;設置文本裝飾線 常見值&#xff1a; None&#xff1a;沒有…

【Ansible】模塊詳解

一、ansible概述 1.1 ansible介紹 Ansible 是一個基于 Python 開發的配置管理和應用部署工具&#xff0c;近年來在自動化管理領域表現突出。它集成了許多傳統運維工具的優點&#xff0c;幾乎可以實現 Pubbet 和 Saltstack 所具備的功能。 1.2 ansible能做什么 批量處理。An…

Git實戰經驗分享:深入掌握git commit --amend的進階技巧

一、工具簡介 git commit --amend是Git版本控制系統的核心補救命令&#xff0c;主要用于修正最近一次提交的元數據。該命令不會產生新的提交記錄&#xff0c;而是通過覆蓋原提交實現版本歷史的整潔性&#xff0c;特別適合在本地倉庫進行提交優化。 二、核心應用場景 提交信息…

軟考 系統架構設計師系列知識點之雜項集萃(56)

接前一篇文章&#xff1a;軟考 系統架構設計師系列知識點之雜項集萃&#xff08;55&#xff09; 第91題 商業智能關注如何從業務數據中提取有用的信息&#xff0c;然后采用這些信息指導企業的業務開展。商業智能系統主要包括數據預處理、建立&#xff08;&#xff09;、數據分…

Spark任務調度流程詳解

1. 核心調度組件 DAGScheduler&#xff1a;負責將Job拆分為Stage&#xff0c;處理Stage間的依賴關系。 TaskScheduler&#xff1a;將Task分配到Executor&#xff0c;監控任務執行。 SchedulerBackend&#xff1a;與集群管理器&#xff08;如YARN、K8s&#xff09;通信&#x…