React
中父组件通过 ref
属性可以操作子组件中暴露的实际 DOM
元素或者暴露的自定义函数。实现父组件操作子组件这一功能,需要子组件经过 forwardRef
这个 API
包裹才能支持。
本文介绍如何使用 forwardRef
这一 API
实现父组件获取和操作子组件。
获取和操作子组件中的实际 DOM 元素
子组件中用 forwardRef
包裹函数组件。并且将第二个参数 ref
传给实际 DOM
元素。
MyInput.js
jsx
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});
在父组件中,通过 ref
属性绑定子组件, 后续便可以通过绑定的 ref
变量来操作子组件中实际的 DOM
元素。如获取元素长度宽度,使元素聚焦的方法。
App.js
jsx
function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
获取子组件中的暴露的函数
在一些场景下,可能需要从父组件中获取到自组件中定义的一些函数。实现这一功能也是通过 forwardRef
包裹函数组件,然后通过 useImperativeHandle
这个 hook
来暴露可被父组件调用的函数。
MyInput.js
jsx
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
在父组件中,通过 ref
属性来操作子组件暴露的函数。
App.js
jsx
import { useRef } from 'react';
import MyInput from './MyInput.js';
export default function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
// This won't work because the DOM node isn't exposed:
// ref.current.style.opacity = 0.5;
}
return (
<form>
<MyInput placeholder="Enter your name" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}