返回

深入React源码之手写实现ref的灵魂拷问

前端

在前端开发中,我们经常会遇到需要在组件中引用子组件实例的情况,比如我们需要访问子组件的属性或方法。在React中,可以使用ref来实现这一需求。

React的ref一共有三种形式:

  • 原生组件的ref
  • 类组件的ref
  • 函数组件的ref

本文将按照源码思想手写实现这三种方式,带你深入理解React ref机制。

原生组件的ref

原生组件的ref是最简单的ref形式,它直接通过DOM API来访问子组件实例。

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

  componentDidMount() {
    console.log(this.childRef.current); // 输出子组件实例
  }

  render() {
    return (
      <div>
        <ChildComponent ref={this.childRef} />
      </div>
    );
  }
}

class ChildComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>我是子组件</h1>
      </div>
    );
  }
}

在父组件中,我们通过React.createRef()创建了一个ref对象,并将它传递给子组件的ref属性。在子组件中,我们可以通过this.props.ref来访问父组件传递的ref对象。

类组件的ref

类组件的ref与原生组件的ref类似,不过它需要使用React.forwardRef()来将ref传递给子组件。

const ChildComponent = React.forwardRef((props, ref) => {
  return (
    <div>
      <h1>我是子组件</h1>
    </div>
  );
});

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

  componentDidMount() {
    console.log(this.childRef.current); // 输出子组件实例
  }

  render() {
    return (
      <div>
        <ChildComponent ref={this.childRef} />
      </div>
    );
  }
}

在父组件中,我们仍然通过React.createRef()创建了一个ref对象,并将它传递给子组件的ref属性。不过,这次我们需要使用React.forwardRef()来将ref传递给子组件。在子组件中,我们可以通过ref参数来访问父组件传递的ref对象。

函数组件的ref

函数组件的ref与类组件的ref类似,不过它需要使用useRef()钩子来创建ref对象。

const ChildComponent = (props) => {
  const ref = useRef(null);

  return (
    <div>
      <h1>我是子组件</h1>
    </div>
  );
};

const ParentComponent = () => {
  const childRef = useRef(null);

  useEffect(() => {
    console.log(childRef.current); // 输出子组件实例
  }, []);

  return (
    <div>
      <ChildComponent ref={childRef} />
    </div>
  );
};

在父组件中,我们通过useRef()创建了一个ref对象,并将它传递给子组件的ref属性。在子组件中,我们可以通过ref参数来访问父组件传递的ref对象。

结语

通过本文,我们手写实现了React ref的三种形式。希望通过本文,大家能够对React ref机制有更深入的理解。