React中useRef、forwardRef、useImperativeHandle用法

React中Ref的使用(尽量少用)

​ref是React提供的用来操纵React组件实例或者DOM元素的接口。表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例。ref可以挂到任何元素上,可以挂到组件上也可以挂载到DOM元素上

Class组件中使用ref

​在React的Class组件时期,我们通过createRef创建ref。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

​在这个例子里ref挂到了原生DOM元素,在这种情况下可以通过ref.current获取到这个DOM元素,并直接调用上面的方法。ref如果挂在到一个Class组件上,这样ref.current获取到的就是这个Class组件的实例

函数式组件中使用ref

​但是,ref不能挂到一个函数式组件(除非使用forwardRef),因为:ref回调函数会在组件被挂载之后将组件实例传递给函数,函数式组件没有实例。

​在函数式组件中通过useRef创建ref。

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

creactRef和useRef的区别

​createRef 只能用在class组件中,useRef 只能用在函数式组件中。createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用。如果在函数式组件中使用createRef创建的ref,其值会随着函数式组件的重新执行而不断初始化。hooks不能用在class组件中,所以class组件只能使用createRef。

forwardRef

  • 前面我们说到:ref不能挂到一个函数式组件(除非使用forwardRef)。
  • forwardRef可以直接包裹一个函数式组件,被包裹的函数式组件会获得被分配给自己的ref(作为第二个参数)。
  • 如果你直接将ref分配给没有被forwardRef包裹的函数式组件,React会在控制台给出错误。
const App: React.FC = () => {
  const ref = useRef(null);

  useEffect(() => {
    ref.current.focus();
  }, []);

  return (
    <>
      <Child ref={ref} />
    </>
  );
};

const Child = forwardRef((props, ref: Ref<any>) => {
  return <input type="text" name="child" ref={ref} />;
});

注意:React.forwardRef参数必须是function,而这个API通常用来解决HOC(高阶组件)中丢失ref的问题。

useImperativeHandle

在forwardRef例子中的代码实际上是不推荐的,因为无法控制要暴露给父组件的值,所以我们使用useImperativeHandle控制要将哪些东西暴露给父组件。
useImperativeHandle 应当与 forwardRef 一起使用
​调用方式:

useImperativeHandle(ref, createHandle, [deps])
  • 接收一个ref
  • 接收一个函数,这个函数返回的对象即是要暴露出的ref
  • 类似useEffect,接收一个依赖数组
const FancyInput=(props, ref) =>{
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} />;
}
export default forwardRef(FancyInput);

​ 在本例中,渲染 的父组件可以调用 inputRef.current.focus()

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值