react教程,forwardRef()如何使用?ref如何跨组件传递?
发布于 作者:苏南大叔 来源:程序如此灵动~
本篇文章的使用场景对于一般人来说,并不常见。因为是用于自定义组件使用的,意思是提供react的各自控件给外部调用的时候,才会用的到forwardRef【而且还可以被普通的ref替代】。而对于控件使用者来说,forwardRef是完全无感的,用到的只有常规的ref。

苏南大叔的程序如此灵动博客,这里记录苏南大叔和计算机代码的故事。本文描述react项目的forwardRef的使用方法。测试环境:create-react-app@5.0.1,react@18.2.0,react-dom@18.2.0,node@16.14.2。
本文主要介绍做组件库时会用到的forwardRef函数,普通情况下是用不到的。平时使用的是ref,请参考:
https://newsn.net/say/react-ref.html
ref不能通过props传递,但是【非ref】可以
由于ref在使用方式上,和普通的props是一样的。
- 对于子组件来说,是否可以通过
props.ref获得ref引用呢?答案是不能。 - 那么,如果把
ref改名成ref2,是否可以获得props.ref2呢?答案是可以。
测试用例为Sunan1:
export class Sunan1 extends React.Component {
state = {who: "苏南大叔"};
componentDidMount() {
console.log(this.props)
}
render() {
return (<div ref={this.props.ref2}>一号子组件(类组件)</div>);
}
}调用方式:
<Sunan1 ref={ref1} ref2={ref2} sn="SN" />测试props输出了ref2和sn这两个props,并且ref2成功作用于div上,并没有输出预期的ref属性。

ref是个被特殊处理的关键字,ref引用指代了子组件本身,在父组件中可以使用ref获得子组件内部数据。比如:
<button onClick={() => { console.log(ref1.current.state.who) }}>1号组件</button>函数组件不能直接使用ref
如果在函数式组件实例上,使用ref,则会有报错信息。
组件定义:
const Sunan2 = (props) => {
console.log(props);
return (<div ref={props.ref}>函数组件与ref</div>);
}组件调用:
function App() {
const ref1 = useRef(null);
return (
<div className="App">
<Sunan2 ref={ref1}>
</div>
);
}
export default App;这个时候会有警告信息提示:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?大意是:ref属性是无法叠加于函数式组件上的,【注意:ref可以直接作用于类组件】。写了ref也没用,但是可以使用React.forwardRef把ref属性给再加工一下。

`ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop.大意是:在组件里面不能使用props.ref。
函数组件可以使用非ref字样
那么,把例子中的ref字样换成ref2字样呢?
组件定义:
const Sunan2 = (props) => {
console.log(props);
return (<div ref={props.ref2}>函数组件与ref</div>);
}组件调用:
function App() {
const ref2 = useRef(null);
return (
<div className="App">
<Sunan2 ref2={ref2}>
</div>
);
}
export default App;结果一切正常,可以正常使用。这是不是比较神奇了。当然,这里在子组件里面,是使用props.ref2获得的ref定义。
forwardRef()
目前的基本结论是:使用ref字样,就会被系统自动过滤掉。如果换成非ref字样,比如ref2字样,就可以通过props.来获取并正常使用ref,但是显然这并不是react希望大家这么做的,官方推荐使用的是:forwardRef()。
子组件定义:
export const Sunan3 = forwardRef(function (props, ref) {
console.log("forwardRef(函数组件)", props, ref);
return (
<>
<input type="text" ref={ref} defaultValue="forwardRef(函数组件)" />
</>
)
});
class Sunan4_ extends React.Component {
componentDidMount() {
console.log("forwardRef(类式组件)", this.props)
}
render() {
return (
<div>
<span ref={this.props.ref2}>forwardRef(类式组件)</span>
</div>
)
}
};
export const Sunan4 = forwardRef((props, ref) => <Sunan4_ ref2={ref} {...props} />);
组件调用:
<Sunan3 ref={ref3} />
<Sunan4 ref={ref4} />
<button onClick={() => { console.log(ref4.current.innerHTML) }}>4号组件</button>forwardRef相关总结
| 组件 | forward中间件ref | 子组件的父组件传递ref | 子组件的父组件传递ref2 |
|---|---|---|---|
| 函数组件 | 警告,系统强制过滤 | 子组件props.ref2 | |
| 类式组件 | 指代子组件,可访问子组件内部 | 子组件this.props.ref2 | |
| forwardRef(函数组件) | 直接传入子组件使用 | 子组件接收两个参数props,ref | 子组件props.ref2 |
| forwardRef(类式组件) | 必须改名非ref | 只在forwardRef()函数内有效 | 子组件this.props.ref2 |
完整代码

App.js:
import React, { createRef, useRef } from "react";
import { Sunan1, Sunan2, Sunan3, Sunan4 } from "./SunanLib";
function App() {
const ref1 = useRef(null);
const ref2 = useRef(null);
const ref3 = useRef(null);
const ref4 = useRef(null);
return (
<div className="App">
<div>
<Sunan1 ref={ref1} ref2={ref2} sn="SN" />
<button onClick={() => { console.log(ref1.current.state.who) }}>1号组件</button>
</div>
<div>
<Sunan2 ref={ref1} ref2={ref2} sn="SN" />
</div>
<div>
<Sunan3 ref={ref3} /></div>
<div>
<Sunan4 ref={ref4} />
<button onClick={() => { console.log(ref4.current.innerHTML) }}>4号组件</button>
</div>
</div>
);
}
export default App;SunanLib.js:
import React, { forwardRef } from "react";
export class Sunan1 extends React.Component {
state = {who: "苏南大叔"};
componentDidMount() {
console.log(this.props)
}
render() {
return (<div ref={this.props.ref2}>一号子组件(类组件)</div>);
}
}
export const Sunan2 = (props) => {
console.log(props);
return (<div ref={props.ref2}>二号子组件(函数组件)</div>);
}
export const Sunan3 = forwardRef(function (props, ref) {
console.log("forwardRef(函数组件)", props, ref);
return (
<>
<input type="text" ref={ref} defaultValue="forwardRef(函数组件)" />
</>
)
});
class Sunan4_ extends React.Component {
componentDidMount() {
console.log("forwardRef(类式组件)", this.props)
}
render() {
return (
<div>
<span ref={this.props.ref2}>forwardRef(类式组件)</span>
</div>
)
}
};
export const Sunan4 = forwardRef((props, ref) => <Sunan4_ ref2={ref} {...props} />);结束语
更多react经验文章,请点击苏南大叔的博客文章: