Skip to content

1.高阶组件:就是一个函数(不算是函数组件,但是可以理解为函数组件,因为函数组件本质上就是一个函数而已)返回值是一个新的组件(函数组件或者 class 组件)

2.forwardRef主要是为了给 函数组件/高阶组件函数 增加接收 ref 的能力(也就是在组件标签上写 ref属性,内部可以进行接收),以便可以在内部使用 Ref 作用于内部元素!

React.forwardRef 详解

React.forwardRef(render)的返回值是react组件,接收的参数是一个 render函数,函数签名为render(props, ref),第二个参数将其接受的 ref 属性转发render返回的组件中。

这项技术并不常见,但在以下两种场景中特别有用:

  • 转发 ref 到组件内部的DOM 节点上
  • 在高阶组件中转发ref

1. 转发 ref到组件内部的DOM节点

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

  1. ref 属性用于 HTML 元素时,接收底层 DOM 元素作为其 current 属性。
  2. ref 属性用于自定义 class 组件时,ref 接收组件实例作为其 current 属性。
  3. 不能在函数组件上使用 ref 属性,因为他们没有实例。

函数组件使用 Ref:

jsx
import React, { useRef } from 'react';

function MyComponent() {
  const ref = useRef(null);

  // 在需要时访问ref
  const handleClick = () => {
    console.log(ref.current);
  };

  return (
    <div>
      <h1 ref={ref}>Hello, World!</h1>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}
jsx
// App.js
import React from 'react';
import Foo from './component/Foo';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.input = React.createRef(); // 1
      // ↑5
  }
  
  handleClick = (e) => {
    const input = this.input.current;
      // 6
    console.log(input);
    console.log(input.value);
    input.focus();
  }
  
  render() {
    return (
      <>
        <button onClick={this.handleClick}>click to get value</button>
                  {/*2*/}
        <Foo ref={this.input}/>
      </>
    )
  }
}
jsx
// Foo.jsx
import React from 'react';
			             // 3
const Foo = React.forwardRef((props, myRef) => {
  return (
    <div>
      <p>....一些其他节点</p>								{/*4*/}
      <input type="text" defaultValue='ref 成功转发到 Foo 组件内部的 input节点上' ref={myRef}/>
      <p>....一些其他节点</p>
      <p>....一些其他节点</p>
    </div>
  );
});

export default Foo;

2. 在高阶组件中转发ref

jsx
// App.js
import React from 'react';
import logProps from './component/logProps';
import Bar from './component/Bar'

const BarWithLogProps = logProps(Bar);
export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Roman',
      age: 23,
      hobby: 'video game'
    }
    this.myRef = React.createRef();
  }
  handleClick = (e) => {
    this.setState({
      name: 'fxy',
      age: 32,
      hobby: 'swim'
    });
    console.log(this.myRef.current);
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick} >click to change props</button>
        <BarWithLogProps {...this.state} ref={this.myRef} />
      </div>
    );
  }
}
jsx
// 最终形态
import React from 'react';

export default function logProps(WrappedComponent) {
  
  class LogProps extends React.Component {
    // 2
    constructor(props) {
      super(props);
      this.state = {
        message: '这是LogProps'
      }
    }
    componentDidUpdate(prevProps) {
      console.log('Previous props: ', prevProps);
      console.log('Current props: ', this.props);
    }
    render() {
      // 3
      const {customRef, ...props} = this.props;
      // 3.5 return <WrappedComponent {...this.props}/>;
      return <WrappedComponent {...props} ref={customRef} />;
    }
  }
  // return LogProps;
  return React.forwardRef((props, ref) => (
    // 1
    <LogProps {...props} customRef={ref} />
  ))
  
}

来源:https://juejin.cn/post/6985068487479656461