阅读量:0
实际应用场景:
组件复用,如当select里面的选项options是走后端动态获取的,如果把网络请求放在组件内部,当单页面多次引用该组件,则获取选项的请求也将发送多次。例如下面这个select组件的CCOptions,需要变量全局化+响应式+懒加载+初始化+性能提升(避免重复请求)。文章末尾附上你需要明白的Vue3 reactive特性!希望你能看到最后。
<t-select popup-props={popProp}> {CCOptions.map((item, index) => ( <t-option key={index} value={item.value} label={item.label} popup-props={{ overlayClassName: "tdesign-demo-select__overlay-option", }} > {item.label} {item.count && <a style="color: var(--td-brand-color)">({item.count})</a>} </t-option> ))} </t-select>
解决问题逻辑:
- 将Function放在全局脚本文件(global.js)内部,按需获取,并且作为导出常量(export const)。例如下面的代码:
// global.ts // 商品类目 export const getCommodityCategoryOptions = async () => { let next_page = CommodityCategoryData.currentPage + 1; let next_pageSize = CommodityCategoryData.pageSize; if ( CommodityCategoryData.Options.length > next_page * next_pageSize || CommodityCategoryData.totalRecords < next_pageSize * (next_page - 1) ) { // 数据已加载过了或者已经加载完毕 return CommodityCategoryData.Options; } await getCommodityCategoryApi({ page: next_page, pageSize: next_pageSize, }) .then((result: any) => { CommodityCategoryData.Options.push( ...map(result.PagedList, (item: any) => { return { label: item.CategoryName ? item.CategoryName : "", value: item.CategoryID, count: item.Count, }; }) ); CommodityCategoryData.totalRecords = result.TotalRecords; CommodityCategoryData.currentPage = result.PageNo; }) .catch((err) => { MessagePlugin.error(err.message); }); return CommodityCategoryData.Options; }; MerchantClassificationData.Options.length >= next_page * next_pageSize || MerchantClassificationData.totalRecords < next_pageSize * (next_page - 1) ) { // 数据已加载过了或者已经加载完毕 return MerchantClassificationData.Options; } await getMerchantClassificationApi({ page: next_page, pageSize: next_pageSize, }) .then((result: MerchantClassificationModel) => { MerchantClassificationData.Options.push( ...map(result.PagedList, (item: MerchantModel) => { return { label: item.CategoryName, value: item.CategoryID, count: item.Count, }; }) ); MerchantClassificationData.totalRecords = result.TotalRecords; MerchantClassificationData.currentPage = result.PageNo; }) .catch((err) => { MessagePlugin.error(err.message); }); return MerchantClassificationData.Options; };
- 将获取到的结果数据存在在全局脚本内部,作为常量就够了(const)。例如下面的代码:
// 商品类目 const CommodityCategoryData: T = { Options: [], totalRecords: 0, currentPage: 0, pageSize: 15, };
- 优化的关键是请求数据的方法避免重复请求,例如分页获取的数据,可以通过判断该数据是否获取过,以此减少请求次数,达到优化性能的目的;
- 数据默认在单页面import的脚本文件里面初始化一次。例如下面的代码:
//另外的脚本文件 export const CCOptions = reactive<Array<{ label: string; value: string; count: number }>>([]); export const getCCOptions = () => { getCommodityCategoryOptions().then((res) => { while (CCOptions.length > 0) CCOptions.pop(); CCOptions.push(...res); }); }; if (Dom_IsExist.formItem_goodsCategory_used) getCCOptions();
- 最后只需要在单页面中引用CCOptions 和getCCOptions 方法就可以实现数据响应式。
import { CCOptions, getCCOptions } from "@/config/appManager";
我的组件业务逻辑:
const popProp = { onScrollToBottom: handleScrollToBottom_MerchantClassification, }; const handleScrollToBottom_MerchantClassification = () => { getCCOptions(); };
<t-select popup-props={popProp}> {CCOptions.map((item, index) => ( <t-option key={index} value={item.value} label={item.label} popup-props={{ overlayClassName: "tdesign-demo-select__overlay-option", }} > {item.label} {item.count && <a style="color: var(--td-brand-color)">({item.count})</a>} </t-option> ))} </t-select>
你需要明白:
1、const+reactive+Array的定义,不能将变量直接=[],因为reactive只响应刚开始那个引用地址;也不能因为报错把const改成let;这样确实不会报错了,但是同样使用=[]之后,变量就不会拥有响应式了。
2、export let CCOptions =
reactive([]);如果使用CCOptions=reactive([…res])则在引用CCOptions的地方也将失去响应式。因为reactive
是跟着括号里面的变量走的;
3、综上所述:while (CCOptions.length > 0) CCOptions.pop();
CCOptions.push(…res);是我实践之后解决该类问题方法