React-hooks 父元件通過ref獲取子元件資料和方法

2023-05-16 12:00:56

我們知道,對於子元件或者節點,如果是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

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)