我们知道,对于子组件或者节点,如果是class类,存在实例,可以通过 React.createRef() 挂载到节点或者组件上,然后通过 this 获取到该节点或组件。
class RefTest extends React.Component{ constructor(props){ super(props); this.myRef=React.createRef(); } componentDidMount(){ console.log(this.myRef.current); } render(){ return <input ref={this.myRef}/> } }
但是在子组件是函数组件的时候,因为函数组件没有实例,所以在正常情况下, ref 是不能挂载函数组件上的。那么此时,我们通过 useImperativeHandle
和 forwardRef
配合就能达到效果。
useImperativeHandle:可以配合 forwardRef 自定义暴露给父组件的实例值。
useImperativeHandle为我们提供了一个类似实例的东西,它帮助我们通过useImperativeHandle 的第二个参数,将所返回的对象的内容挂载到父组件的 ref.current 上.
useImperativeHandle 接收三个参数:
① 第一个参数 ref:接收 forWardRef 传递过来的 ref。
② 第二个参数 createHandle:处理函数,返回值作为暴露给父组件的 ref 对象
③ 第三个参数 deps:依赖项 deps,依赖项更改形成新的 ref 对象。
forwardRef 会创建一个 React 组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。
下面举一个实际例子,方便大家理解:
// 子组件 const CollectAmountFormItem = forwardRef(({ isDisabled, val, handleChange }: Props, onRef: any) => { const [isShow, setIsShow] = useState<boolean>(val == 1); // 是否展示募集资金和剩余募集资金 // 暴露给父组件的属性 useImperativeHandle(onRef, () => ({ isShow, setIsShow })); useEffect(() => { if (val == 1) setIsShow(true) else setIsShow(false) }, [val]) /** * 是否募集回调 * @param val 下拉框id * @param option 下拉框对象 */ const handleSelect = (val: any, option: any) => { setIsShow(val == 1); handleChange && handleChange(val, option); }; return ( <> <Col xs={20} sm={16} md={12} lg={8} xl={6}> <Form.Item name="isRaiseMoney" label="是否募集资金" rules={[{ required: true }]}> <Select placeholder="请选择" disabled={isDisabled} onChange={handleSelect}> <Select.Option value={1}>是</Select.Option> <Select.Option value={0}>否</Select.Option> </Select> </Form.Item> </Col> { isShow && ( <> <Col xs={20} sm={16} md={12} lg={8} xl={6}> <Form.Item name="usedMoney" label="已使用资金" rules={[{ required: isShow }]}> <InputNumber formatter={value => `${value}`.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')} parser={value => `${value}`.replace(/\$\s?|(,*)/g, '')} style={{width: '100%'}} precision={2} disabled placeholder="自动计算" /> </Form.Item> </Col> <Col xs={20} sm={16} md={12} lg={8} xl={6}> <Form.Item name="remainMoney" label="剩余资金" rules={[{ required: isShow }]}> <InputNumber formatter={value => `${value}`.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')} parser={value => `${value}`.replace(/\$\s?|(,*)/g, '')} style={{width: '100%'}} precision={2} disabled placeholder="自动计算" /> </Form.Item> </Col> </> ) } </> ) })
// 在父组件中使用 // 1、首先引入该子组件 import CollectAmountFormItem from '@/components/CollectAmountFormItem'; // 2、定义一个ref const collectRef = useRef<any>() // 3、使用 <CollectAmountFormItem isDisabled={isDisable} val={formData.isRaiseMoney} ref={collectRef} handleChange={handleChangeAmount} /> // 然后就可以在父组件中的一些方法中获取子组件暴露出来的方法或值,比如: collectRef.current.setIsShow(false)