父组件如何获得子组件的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);
这样在高阶组件中在转发一下同样达到了我们的目的~