跳到主要内容

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})

传入配置项 oncetrue 即可。

API

useDataSetEvents(
dataSet: DataSet,
eventNames: string | string[],
handler: CallableFunction | CallableFunction[],
options?: AddEventListenerOptions
)

参数

参数说明类型默认值
dataSetDataSet 实例DataSet-
eventNames事件名称string ⎮ string[]-
handler处理函数CallableFunction ⎮ CallableFunction[]-
options(可选)选项Options-

Options

参数说明类型默认值
once可选项,handler 在添加之后最多只调用一次。如果是 truehandler 会在其被调用之后自动移除。booleanfalse
capture可选项,handler 会在该 DataSet 类型的事件捕获阶段传播到该 EventTarget 时触发。booleanfalse
passive可选项,设置为 true 时,表示 handler 永远不会调用 preventDefault()booleanfalse
此 hook 维护者:黄振敏

9.2.2. 动态渲染业务对象字段操作符对应的组件(useBusinessObjectOperator)

主要用于接收业务对象的 businessObjectCodebusinessObjectFieldCode, 确定操作符和选择完操作符后返回的组件。

useBusinessObjectOperator 中使用了 ahooks 中的 useRequest 方法, 会对接口请求结果进行缓存,如果不同页面传入相同业务对象 code 会直接读取上一次接口请求过的结果。

基础用法

useBusinessObjectOperator 需要接收 businessObjectCodebusinessObjectFieldCode 两个参数,页面上至少要有一个选择业务对象的组件产生选择完的结果。 这个组件由开发者自定义。

同时,页面上也需要一个 Select 组件用于渲染操作符的选择。当传入了 businessObjectCodebusinessObjectFieldCode 参数,接口会进行请求后端结果,返回值第一个参数返回页面上需要展示的操作符选项。需要把用户选择完的结果作为第二个入参。

选择完业务对象和操作符后,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. 对于返回数组数值的组件(多选、范围类型组件),如何以字符串形式传给后端?

在一部分场景中,后端仅接收字符串类型的数值,因此在回显和提交数据是要分别做数据类型转换。
可以使用工具方法 renderComponentarrayConnector 参数处理回显的数据。

  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,
};
},
},
});
此 hook 维护者:黄振敏