目录

类组件中使用

ref='myRef'(React中不推荐)

createRef(推荐)

回调Ref (推荐)

函数组件中使用

React.useRef

React.forwardRef

React.useImperativeHandle


由于函数组件中没有实例,所以区分2种用法。

类组件中使用

注意你不能在函数组件上使用下面的ref 属性,因为他们没有实例。

ref='myRef'(React中不推荐)

和vue中的ref方法使用相同,在元素上添加ref=‘myRef’,然后通过this.refs.myRef访问绑定的dom节点。不推荐使用,且会有一大堆飘红,但还是可以用。

 

createRef(推荐)

创建一个能够通过 ref 属性附加到 React 元素的 ref,需要通过点current访问dom节点或组件实例

ref 的值根据节点的类型而有所不同:

  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性(例如下面this.inputRef.current为input的dom节点)。
  • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
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 (推荐)

它能助你更精细地控制何时 refs 被设置和解除。React 将在组件挂载时,会调用 ref 回调函数并传入 DOM 元素,当卸载时调用它并传入 null

在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。所以在 componentDidMount 或 componentDidUpdate 触发前,React 会保证 refs 一定是最新的。

注意这里的ref不用通过点current,直接是doom节点或组件的实例。

import React, { PureComponent } from 'react';
class App extends PureComponent {
    constructor(props) {
        super(props)
        this.titleRef = null     // 定义一个初始值
    }
    render() {
        return (
            <div>
                <h1 ref={arg => this.titleRef = arg}>Hello,React</h1>
                <button onClick={e => this.changeText()}>函数改变文本</button>
            </div>
        );
    }
    changeText() {
        console.log(this.titleRef)
        this.titleRef.innerHTML = "Hello,yf"
    }
}
export default App;

 

函数组件中使用

refs组件中的使用class组件的使用,函数组件是不支持的,因为函数组件是没有实例的。

React.useRef

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue通常为null)。返回的 ref 对象在组件的整个生命周期内持续存在。

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

 当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调ref来实现

 

React.forwardRef

将子组件ref暴露出去,在父组件上绑定ref获取子组件内绑定的ref。

函数组件通过React.forwardRef创建后,才可以在该组件上绑定ref属性,并且ref属性绑定的值是该组件内的ref绑定的dom节点而非该组件的实例。在该组件内ref只是回调ref函数,并不能在组件内访问

注意下面的Test才是组件名。

import React, { PureComponent, forwardRef } from "react";
const Test = forwardRef(function Profile(props, ref) {
  React.useEffect(() => {
    console.log(ref); //arg => this.titleRef = arg
  }, []);
  return (
    <>
      <h1>h1</h1>
      <h2 ref={ref}>h2</h2>
    </>
  );
});
class App extends PureComponent {
  constructor(props) {
    super(props);
    this.titleRef = null; // 定义一个初始值
  }
  render() {
    return (
      <div>
        <Test ref={(arg) => (this.titleRef = arg)}></Test>
        <button onClick={(e) => this.changeText()}>函数改变文本</button>
      </div>
    );
  }
  changeText() {
    console.log(this.titleRef);
    this.titleRef.innerHTML = "Hello wrld";
  }
}
export default App;

 

React.useImperativeHandle

搭配forwardRef一起使用,这是暴露在父组件的ref是useImperativeHandle函数第二个参数返回的对象。

import React, { PureComponent, forwardRef } from "react";
function FancyInput(props, ref) {
  const inputRef = React.useRef();
  React.useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    a(){
      console.log(inputRef)
    }
  }));
  return <input ref={inputRef }/>;
}
FancyInput = forwardRef(FancyInput);
class App extends PureComponent {
  constructor(props) {
    super(props);
    this.fancyRef = null; // 定义一个初始值
  }
  render() {
    return (
      <>
        <FancyInput ref={(arg) => (this.fancyRef = arg)} />
        <div onClick={()=>{this.changeText()}}>click</div>
      </>
    );
  }
  changeText() {
    console.log(this.fancyRef); //{focus: ƒ, a: ƒ}
    this.fancyRef.focus() //input聚焦
  }
}
export default App;

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐