目录
- 背景
- 思考
- 实现
- 知识点总结
-
- [uesRef() 作对象处理](#uesRef() 作对象处理)
- [useImperativeHandle() 父组件操作引入子组件的内部方法](#useImperativeHandle() 父组件操作引入子组件的内部方法)
- 最后
背景
之前项目中使用了antd pro
中的 可编辑表格 (EditableProTable)
,在页面中表格要经过多层遍历后组成的新页面,所以我将之抽成了一个公用的组件,另外在遍历的最外层需要通过一个按钮统一提交表格数据,但是提交数据之前需要对每一个表格进行非空校验。
思考
遍历中引入组件这个没啥好说的,根据以往的经验来说,一般要获取某个 JSX
节点都是采用的 useRef()
这个Hook
,大多写法如下:
typescript
const ref = useRef(null);
<div ref={ref}>...</div>
这里主要说的是怎么一次性获取多个子组件实例,用到这个场景的也有,可能也不大多,我刚开始也在网上找了一大堆,基本没有相关的答案,这整的我 cv大法
自然也用不了,可是项目又赶得急,总的想办法解决吧,最后我盯上了ChtGPT
,通过智能答案在这里获取到了一定的参考,如下:
既然已经有了灵感(参考),那就依样画葫芦呗,开整。
下面是我经过项目实践后,再次做的一个案例,希望能够对有需要的朋友一些帮助,可能写的不够优雅,还请大家多多包涵。如有更好的方式,请大家多多留言扶正,多谢。
实现
完整代码:
typescript
import { Button, message } from "antd";
import { useImperativeHandle, useRef } from "react";
interface paramsType {
id: number,
title: string,
}
interface validateFieldsObjType {
[key: number]: boolean;
}
// 子组件
const ChildComponentPage:React.FC = (props: any) => {
const { id, title, onRef } = props;
const divStyleObj = {
width: '100%',
height: '100px',
background: 'red',
marginTop: '20px',
fontSize: '20px',
color: '#fff'
}
useImperativeHandle(onRef, () => {
return {
func
}
})
const func = ():boolean => {
console.log(`${title}(${id})被触发了`)
if (id ===2) return false;
else return true;
}
return (
<div style={divStyleObj}>【子组件】==》{title}--{id}</div>
)
}
// 父组件
const TestRef:React.FC = () => {
const childRefs: any = useRef({});
// mock源数据
const datasource:paramsType[] = [
{ id: 1, title: '组件-天天', },
{ id: 2, title: '组件-小灰', },
{ id: 3, title: '组件-阿奇', },
{ id: 4, title: '组件-驽马', },
{ id: 5, title: '组件-小栗', },
]
// 异步获取所有子组件校验状态
const getChildRefReturnStateFn = (childRefIdsArry:any) => {
const validateFieldsObj: validateFieldsObjType = {};
childRefIdsArry.forEach((id: number, index: number) => {
const childRef = childRefs.current[id];
const childReturnState = childRef.func();
console.log('子组件实例返回状态:', id, childReturnState)
validateFieldsObj[id] = childReturnState;
})
return validateFieldsObj;
}
// 点击事件
const clickThisFn = async () => {
const childRefIdsArry:any[] = Object.keys(childRefs.current);
const validateFieldsObj: any = await getChildRefReturnStateFn(childRefIdsArry);
console.log('子组件检查结果:', validateFieldsObj)
const validateFieldsLen = Object.values(validateFieldsObj).filter((type)=>!type);
if (childRefIdsArry.length !== validateFieldsLen.length) console.log('校验不通过,请再次检查数据。')
else console.log('校验已通过')
};
return (
<>
<div style={{ width: '100%', background: 'orange', padding: '20px' }}>
{
datasource.map(({ id, title }: paramsType, index: number) => {
return <ChildComponentPage key={id} id={id} title={title} onRef={(_ref: React.RefObject<HTMLInputElement>) => childRefs.current[id] = _ref} />
})
}
</div>
<Button type="primary" onClick={clickThisFn}>检验全部子组件</Button>
</>
)
};
export default TestRef;
成功运行后的界面如下:
点击左侧按钮后,通过控制台可以看到相关的运行信息。
知识点总结
uesRef() 作对象处理
useImperativeHandle() 父组件操作引入子组件的内部方法
最后
关于这个问题的解决方法,就在上面的代码里面了,如果对上面的Hook使用还不清楚的,这里就不再赘述,请自行网上查看。
如果对你有所帮助,麻烦咚咚你的黄金手指,请点赞
,搜藏
。