父組件如何獲得子組件的Ref
在我們實際開發的過程當中難免會遇到父組件想要獲得子組件的ref進行一些操作的時候,那麼我們怎麼做呢?
筆者給大家提供倆種方法:
一:使用React.forwardRef
這是react官方文檔中給我們說明的,我們照着文檔做即可,
筆者演示如下:
父組件代碼
// 可以寫倆種形式,class組件或者hook組件皆可
// class組件
import React, {Component} from 'react';
import Children from "../components/children";
export default class Test extends Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
render() {
return (
<div>
我是父組件
<p onClick={() => console.log(this.buttonRef)}>我要獲取子組件button的ref</p>
<Children ref={this.buttonRef}>我是子組件啊!!!</Children>
</div>
)
}
}
// hook組件
import React, { useRef } from 'react';
import Children from "../components/children";
export default function Test(props) {
const buttonRef = useRef();
return (
<div>
我是父組件
<p onClick={() => console.log(buttonRef)}>我要獲取子組件button的ref</p>
<Children ref={buttonRef}>我是子組件啊!!!</Children>
</div>
);
}
子組件代碼
import React from 'react';
const Children = React.forwardRef((props, ref) => {
return (
<button ref={ref}>
{props.children}
</button>
)
});
export default Children;
這個時候當我們點擊p標籤的時候就成功console出了子組件的button的ref。
解析:
- 我們通過調用 React.createRef 創建了一個 React ref 並將其賦值給 ref 變量。
- 我們通過指定 ref 爲 JSX 屬性,將其向下傳遞給 <Children ref={ref}>。
- React 傳遞 ref 給 forwardRef 內函數 (props, ref) => …,作爲其第二個參數。
- 我們向下轉發該 ref 參數到 <button ref={ref}>,將其指定爲 JSX 屬性。
- 當 ref 掛載完成,ref.current 將指向 DOM 節點。
注意事項:
第二個參數 ref 只在使用 React.forwardRef 定義組件時存在。常規函數和 class 組件不接收 ref 參數,且 props 中也不存在 ref。
Ref 轉發不僅限於 DOM 組件,你也可以轉發 refs 到 class 組件實例中。
缺點:只能轉發一個。
二:在子組件初始化的時候將ref通過事件傳遞給父組件
這個方法就是我們借用react組件數據傳遞和生命週期概念來進行傳遞ref給父組件。
筆者提供的演示代碼:
父組件
import React, { useState } from 'react';
import Children from "../components/children";
export default function Test(props) {
const [refs, setRefs] = useState([]);
return (
<div>
我是父組件
<p onClick={() => console.log(refs)}>我要獲取子組件button的ref</p>
<Children onRef={(refs) => {setRefs(refs)}}>我是子組件啊!!!</Children>
</div>
);
}
子組件
import React, { useRef, useEffect } from 'react';
function Children({ onRef = () => {}, children = null}) {
const buttonRef = useRef();
const aRef = useRef();
useEffect(() => {
onRef([buttonRef, aRef])
}, []);
return (
<div>
<button ref={buttonRef}>
{children}
</button>
<br />
<a href="" ref={aRef}>我就是來試試</a>
</div>
);
}
export default Children;
這樣我們就能想要傳幾個ref給父組件就傳幾個了
三、高階組件轉發ref
父組件
import React, { useState, useRef } from 'react';
import Children from "../components/children";
export default function Test(props) {
const buttonRef = useRef();
return (
<div>
我是父組件
<p onClick={() => console.log(buttonRef)}>我要獲取子組件button的ref</p>
<Children ref={buttonRef}>我是子組件啊!!!</Children>
</div>
);
}
高階組件
import React from 'react';
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 將自定義的 prop 屬性 “forwardedRef” 定義爲 ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// 注意 React.forwardRef 回調的第二個參數 “ref”。
// 我們可以將其作爲常規 prop 屬性傳遞給 LogProps,例如 “forwardedRef”
// 然後它就可以被掛載到被 LogProps 包裹的子組件上。
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
export default logProps;
子組件
import React from 'react';
import LogProps from './LogProps';
const Children = React.forwardRef((props, ref) => {
return (
<button ref={ref}>
{props.children}
</button>
)
})
export default LogProps(Children);
這樣在高階組件中在轉發一下同樣達到了我們的目的~