ref:用来绑定到HTML元素或者组件上,获取其DOM;
forwardRef:帮助子组件拿到父组件中子组件上面绑定的ref,绑定到自己的某一个元素中。这样就将子组件的DOM直接暴露给了父组件。这种方式存在的弊端:
1. 直接暴露给父组件带来的问题是某些情况的不可控
2. 父组件可以拿到DOM后进行任意的操作
3. 只是希望父组件可以操作某些方法,并不希望它随意操作其他方法
useImperativeHandle:减少暴露给父组件获取的DOM元素属性, 只暴露给父组件需要用到的DOM方法。有两个参数:
1. 参数1: 父组件传递的ref属性
2. 参数2: 函数,返回一个对象,可在父组件中通过ref.current调用该对象中的方法
目录结构如下:
代码如下:
App.js:
import './App.css';
import ChangeRef from './changeRef/ChangeRef'
function App() {
return (
<ChangeRef />
);
}
export default App;
ChangeRef.js(父组件):
//父组件
import React, { useRef } from "react";
import Child from "./ChangeRefChild";
const ChangeRef = () => {
const childRef= useRef(); // 组件的ref
return (
<div>
<button
onClick={() => {
console.log(childRef.current);
childRef.current.focus() // 获取子组件暴露的focus事件
childRef.current.getData(345) // 给子组件的getData函数传参
}}
>
聚焦input
</button>
<Child ref={childRef} a={11}></Child>
</div>
);
};
export default ChangeRef;
ChangeRefChild.js(子组件):
import React, {useState, forwardRef, useImperativeHandle, useRef} from 'react'
const ChangeRefChild = forwardRef((props, ref) => {
console.log(props, ref); // {a: 11} {current: undefined}
const inputRef = useRef();
const [text, setText] = useState('123');
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getData: (abc) => {
console.log(abc);
setText(abc)
}
}))
return (
<>
<input type="text" ref={inputRef} />
<p>{text}</p>
</>
)
})
export default ChangeRefChild
运行结果:
点击按钮后: