目录
1. Refs
1.1. Refs 适合干什么
1.2. 创建、添加、访问 Refs
1.3. Callback Refs
2. Forwarding Refs
3. Hooks
3.1. useRef
3.2. useImperativeHandle
1. Refs
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
勿过度使用 Refs
1.1. Refs 适合干什么
1.2. 创建、添加、访问 Refs
// 创建 Refs
this.myRef = React.createRef();
// 添加 Refs
<SomeClassComponent ref={this.myRef}/>
<someHtmlElement ref={this.myRef}/>
// 引用 Refs
const node = this.myRef.current;
示例1:ref->DOM
import React from "react"
class HelloWorld extends React.Component{
constructor(props) {
super(props);
this.myRef = React.createRef<HTMLInputElement>();
}
componentDidMount(): void {
this.myRef.current.value = "HelloWorld!";
this.myRef.current.focus();
}
render() {
return <input ref={this.myRef} type={"text"} />;
}
}
export default function App(){
return (
<HelloWorld/>
);
}
示例2:ref->class 组件
import React from "react"
class HelloWorld extends React.Component{
constructor(props) {
super(props);
this.myRef = React.createRef();
}
changeBgColor(bgcolor): void {
this.myRef.current.style.backgroundColor = bgcolor;
}
render() {
return <input ref={this.myRef} type={"text"} />;
}
}
export default class App extends React.Component{
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount(): void {
this.myRef.current.changeBgColor("purple");
}
render() {
return <HelloWorld ref={this.myRef}/>;
};
}
1.3. Callback Refs
除了使用 createRef() 创建的 ref 属性,React 也支持通过 callback 设置 refs。
示例:
import React from "react"
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// 使用原生 DOM API 使 text 输入框获得焦点
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// 组件挂载后,让文本框自动获得焦点
this.focusTextInput();
}
render() {
// 使用 `ref` 的回调函数将 text 输入框 DOM 节点的引用存储到 React
// 实例上(比如 this.textInput)
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
export default function App(){
return <CustomTextInput/>
}
示例2:Parent direct visit child's DOM
import React from "react"
function CustomTextInput(props) {
return (
<div>
{/* eslint-disable-next-line react/prop-types */}
<input ref={props.inputRef}/>
</div>
);
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.inputElement = null;
}
focusTextInput = () => {
if (this.inputElement) {
this.inputElement.focus();
}
}
saveInputRef = (el) => {
this.inputElement = el;
}
render() {
return (
<div>
<CustomTextInput inputRef={this.saveInputRef}/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
export default function App() {
return <Parent/>
}
Parent 把它的 refs 回调函数当作 inputRef props 传递给了 CustomTextInput,而且 CustomTextInput 把相同的函数作为特殊的 ref 属性传递给了 <input>。结果是,在 Parent 中的 this.inputElement 会被设置为与 CustomTextInput 中的 input 元素相对应的 DOM 节点。
2. Forwarding Refs
Ref 转发允许某些组件接收 ref,并将其向下传递(或者说“转发”)给子组件。
勿过度使用 Refs
API:
React.forwardRef
示例1:React.forwardRef
import React from "react"
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
export default class App extends React.Component{
constructor(props) {
super(props);
this.ref = React.createRef();
}
componentDidMount(): void {
console.log(this.ref.current);
}
render(){
return <FancyButton ref={this.ref}>Click me!</FancyButton>;
}
}
示例2:HOC + Forwarding Refs
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} />;
});
}
示例3:HOC + Forwarding Refs + React Dev Tools
React.forwardRef 接受一个渲染函数。React DevTools 使用该函数来决定为 ref 转发组件显示的内容。
import React from "react"
class FancyButton extends React.Component {
focus() {
// ...
}
render(){
return "FancyButton";
}
}
// HOC
function logProps(Component) {
class LogProps extends React.Component {
render() {
const {forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// 如果命名了渲染函数,DevTools 也将包含其名称(例如 “ForwardRef(myFunction)”)
function myForwardRef(props, ref){
return <LogProps {...props} forwardedRef={ref} />;
}
return React.forwardRef(myForwardRef);
}
// HOC(FancyButton)
const WrappedFancyButton = logProps(FancyButton);
export default class App extends React.Component{
constructor(props) {
super(props);
this.ref = React.createRef();
}
componentDidMount(): void {
console.log(this.ref.current);
}
render(){
return <WrappedFancyButton ref={this.ref}/>;
}
}
3. Hooks
勿过度使用 Refs
3.1. useRef
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
示例:
import React, {useRef} from "react"
function HelloWorld(){
const myRef = useRef(null);
const onButtonClick = () => {
myRef.current.value = "HelloWorld!";
myRef.current.focus();
}
return (<>
<input ref={myRef} type="text" />
<button onClick={onButtonClick}>Click</button>
</>);
}
export default function App(){
return (
<HelloWorld/>
);
}
3.2. useImperativeHandle
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。useImperativeHandle 应当与 React.forwardRef 一起使用:
示例:
import React, {useRef, useEffect, useImperativeHandle} from "react"
function HelloWorld(props, ref){
const myRef = useRef(null);
useImperativeHandle(ref, ()=>({
changeBgColor(bgcolor) {
myRef.current.style.backgroundColor = bgcolor;
}
}));
return <input ref={myRef} type={"text"} />;
}
HelloWorld = React.forwardRef(HelloWorld);
export default function App(){
const myRef = useRef(null);
useEffect(()=>{
myRef.current.changeBgColor("purple");
});
return <HelloWorld ref={myRef}/>;
}
参考:
https://react.docschina.org/docs/hooks-reference.html#useref
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有