9.2. 公共 hooks
9.2.1. 批量 DataSet 事件监听(useDataSetEvents
)
支持监听同一个 DataSet
的单个或多个
事件,在 DataSet
实例变化时,会重新生成新的监听。
使用示例
单个事件监听:
useDataSetEvents(ds,'update',()=>{XXX})
多个事件依次监听:
useDataSetEvents(ds,['select','unSelect'],[()=>{XXX},()=>{XXX}])
一个回调监听多个事件:
useDataSetEvents(ds,['select','unSelect'],()=>{XXX})
只监听一次:
useDataSetEvents(ds,'select','unSelect',()=>{XXX},{once:true})
传入配置项 once
为 true
即可。
API
useDataSetEvents(
dataSet: DataSet,
eventNames: string | string[],
handler: CallableFunction | CallableFunction[],
options?: AddEventListenerOptions
)
参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
dataSet | DataSet 实例 | DataSet | - |
eventNames | 事件名称 | string ⎮ string[] | - |
handler | 处理函数 | CallableFunction ⎮ CallableFunction[] | - |
options(可选) | 选项 | Options | - |
Options
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
once | 可选项,handler 在添加之后最多只调用一次 。如果是 true ,handler 会在其被调用之后自动移除。 | boolean | false |
capture | 可选项,handler 会在该 DataSet 类型的事件捕获阶段传播到该 EventTarget 时触发。 | boolean | false |
passive | 可选项,设置为 true 时,表示 handler 永远不会调用 preventDefault() 。 | boolean | false |
9.2.2. 动态渲染业务对象字段操作符对应的组件(useBusinessObjectOperator
)
主要用于接收业务对象的 businessObjectCode
和 businessObjectFieldCode
, 确定操作符和选择完操作符后返回的组件。
useBusinessObjectOperator
中使用了 ahooks 中的 useRequest
方法, 会对接口请求结果进行缓存,如果不同页面传入相同业务对象 code
会直接读取上一次接口请求过的结果。
基础用法
useBusinessObjectOperator
需要接收 businessObjectCode
和 businessObjectFieldCode
两个参数,页面上至少要有一个选择业务对象的组件产生选择完的结果。
这个组件由开发者自定义。
同时,页面上也需要一个 Select
组件用于渲染操作符的选择。当传入了 businessObjectCode
和 businessObjectFieldCode
参数,接口会进行请求后端结果,返回值第一个参数返回页面上需要展示的操作符选项。需要把用户选择完的结果作为第二个入参。
选择完业务对象和操作符后,useBusinessObjectOperator
返回值第二个参数会返回组件JSX元素
,开发者可通过 React.cloneElement
自定义注入参数或者
使用返回的工具函数 renderComponent
来渲染组件.
enum FieldsNames {
BUSINESS_OBJECT = 'businessObject',
OPERATOR_TYPE = 'operatorType',
VALUE = 'value',
}
const Demo = () => {
const dataSet = new DataSet({
autoCreate: true,
fields: [
{
name: FieldsNames.BUSINESS_OBJECT,
lovCode: 'HMDE.BUSINESS_OBJECT.SITE',
type: FieldType.object,
},
{
name: FieldsNames.OPERATOR_TYPE,
textField: 'meaning',
valueField: 'value',
type: FieldType.string,
},
{
name: FieldsNames.VALUE,
type: FieldType.string,
},
]
});
const [optionalOperators, dynamicComponent, dComponentOptionalProps] = useBusinessObjectOperator(
{
businessObjectCode: dataSet.current?.get(FieldNames.BUSINESS_OBJECT)?.businessObjectCode,
businessObjectFieldCode: dataSet.current?.get(FieldNames.BUSINESS_OBJECT)?.businessObjectFieldCode,
},
dataSet.current?.get(FieldNames.OPERATOR_TYPE)
);
const renderDynamicComponent = () => {
if (!dynamicComponent) return null;
const { componentName, componentProps, renderComponent } = dComponentOptionalProps;
return renderComponent(dataSet, FieldsNames.VALUE, {
arrayConnector: ',', // 兼容后端字符串存储,如果是数组, 则使用这个连接符转成数组
handleRenderProps() {
// 动态注入渲染时组件所需的 props
if (componentProps.range) {
return { label: 'test-range' };
}
return { label: 'test' };
},
});
}
return (
<Form dataSet={dataSet}>
<Lov name="businessObject" />
<Select name="operatorType" options={optionalOperators} notFoundContent={dComponentOptionalProps.loading ? '加载中...' : '暂无数据'} />
{dataSet.current?.get('operatorType') && renderDynamicComponent()}
</Form>
)
}
自定义渲染
useBusinessObjectOperator
返回的组件是一个 JSX 元素,因此想要注入属性必须通过 React.cloneElement
来实现.
enum FieldNames {
BUSINESS_OBJECT = 'businessObject',
OPERATOR_TYPE = 'operatorType',
VALUE = 'value',
}
const Demo = () => {
const dataSet = new DataSet({
autoCreate: true,
fields: [
{
name: FieldNames.BUSINESS_OBJECT,
lovCode: 'HMDE.BUSINESS_OBJECT.SITE',
},
{
name: FieldNames.OPERATOR_TYPE,
textField: 'meaning',
valueField: 'value',
},
{
name: FieldNames.VALUE,
type: FieldType.string,
},
]
});
const [optionalOperators, dynamicComponent, dComponentOptionalProps] = useBusinessObjectOperator(
{
businessObjectCode: dataSet.current?.get(FieldNames.BUSINESS_OBJECT)?.businessObjectCode,
businessObjectFieldCode: dataSet.current?.get(FieldNames.BUSINESS_OBJECT)?.businessObjectFieldCode,
},
dataSet.current?.get(FieldNames.OPERATOR_TYPE)
);
const renderDynamicComponent = () => {
if (!dynamicComponent) return null;
const { componentName, componentProps, renderComponent } = dComponentOptionalProps;
// 使用 `React.cloneElement` 来注入属性
const cloneComponent = (_props) =>
React.cloneElement(dynamicComponent, {
name: 'value',
label: 'test',
..._props,
});
const popupProps: any = {
popupStyle: { zIndex: 1 },
getPopupContainer: (triggerNode) => triggerNode?.parentNode as HTMLElement,
};
switch (componentName) {
case 'Select':
case 'Lov':
// getDataSetProps 为提供的工具函数, 用于辅助生成 Select/Lov 组件的 dataSet(主要是 lookupCode 和 lovCode)
popupProps.dataSet = new DataSet(
getDataSetProps({ dataKey: FieldNames.VALUE, parentDataSet: dataSet })
);
return cloneComponent(popupProps);
case 'DatePicker':
case 'DateTimePicker':
return cloneComponent(popupProps);
default:
return cloneComponent({});
}
}
return (
<Form dataSet={dataSet}>
<Lov name="businessObject" />
<Select name="operatorType" options={optionalOperators} notFoundContent={dComponentOptionalProps.loading ? '加载中...' : '暂无数据'} />
{dataSet.current?.get('operatorType') && renderDynamicComponent()}
</Form>
)
}
参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
businessObject | 业务对象字段 | {businessObjectCode:string, businessObjectFieldCode:string } | - |
selectedOperatorType | 选择的操作符 | string |
返回值
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
optionalOperators | 当前可选的给受控 Select 组件的操作符 | DataSet | - |
component | 根据操作符产生的组件 | JSX Element | |
componentOptionalProps | 一些辅助字段和工具函数 | ComponentOptionalProps |
ComponentOptionalProps
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
customOptionList | 业务对象自定义的集合数据 | CustomOptionList | - |
lovCode | 值集 code(注意区分 Select 和 Lov 组件) | string | |
required | 是否必输 | boolean | |
componentName | 组件名称 | string | |
componentProps | 组件属性 | object | |
getDataSetProps | 工具函数辅助生成 Select Lov 组件的 ds 对象 | ({dataKey?:string;parentDataSet?: DataSet ⎮ Record; fieldProps:FieldProps })=> DataSetProps | |
compatibleArray | 兼容数组格式的工具方法 | (ds:DataSet ⎮ Record, dataKey:string, arrayConnector?:string)=> void | |
renderComponent | 渲染组件的辅助方法 | (ds: DataSet ⎮ Record, dataKey: string,{arrayConnector?:string,handleRenderProps?: ()=> Object, selectLovFieldProps: FieldProps})=> | |
data | 完整的后端数据 | BusinessObjectOperatorProps | |
loading | 接口 loading 状态 | boolean |
FAQ
1. 在使用字段钻取组件传入业务对象参数时注意事项
因为字段钻取组件允许选到关联的业务对象
,所以在使用时需要注意要给 useBusinessObjectOperator
传入最后一个钻取到的 businessObjectCode
。
<DrillComponent
businessObjectCode={businessObjectCode}
drillMainKeyType={EDrillMainKeyType.ALL}
onChange={(res)=>{
// res.businessObjectCode 就是返回的字段钻取组件最后一层的业务对象编码
}}
/>
2. 对于返回数组数值的组件(多选、范围类型组件),如何以字符串形式传给后端?
在一部分场景中,后端仅接收字符串类型的数值,因此在回显和提交数据是要分别做数据类型转换。
可以使用工具方法 renderComponent
的 arrayConnector
参数处理回显的数据。
const renderDynamicComponent = () => {
if (!dynamicComponent) return null;
const { componentName, componentProps, renderComponent } = dComponentOptionalProps;
return renderComponent(dataSet, FieldsNames.VALUE, {
// 兼容后端字符串存储,如果是数组, 则使用这个连接符转成数组
arrayConnector: ',',
// ......
});
}
在提交数据时,需要使用 toString
方法转成字符串。
const demoDS = (): DataSetProps => ({
// ......
transport: {
update: ({ data }) => {
const _data = Array.isArray(data) ? data[0] : { __id: "", _status: "" };
// 数组类型
_data.permissionDataFilterList = _data.permissionDataFilterList.map(
(v) => ({
...v,
// 使用 toString 把数组转成字符串
rightValue: v.rightValue?.toString(),
})
);
return {
url: `XXXXXX`,
method: "PUT",
data: _data,
};
},
},
});