React高阶组件中使用ref

react中forwardRef是用来解决HOC组件使用ref的问题的,所谓HOC就是Higher Order Component,比如使用redux的时候,我们用connect来给组件绑定需要的state,这其中其实就是给我们的组件在外部包了一层组件,然后通过…props的方式把外部的props传入到实际组件。forwardRef的使用方法如下:

const TargetComponent = React.forwardRef((props, ref) => (
  <TargetComponent ref={ref} />
))

传递进去,转发displayName;

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;
      // 将自定义的 prop 属性 “forwardedRef” 定义为 ref
      return <Component ref={forwardedRef} {...rest} />;    }
  }

  // 注意 React.forwardRef 回调的第二个参数 “ref”。
  // 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
  // 然后它就可以被挂载到被 LogProps 包裹的子组件上。
  return React.forwardRef((props, ref) => {  
      return <LogProps {...props} forwardedRef={ref} />;  
  });
}


// 你可以直接获取 DOM 的 ref:
const ref = React.createRef();
const App = logProps(SubApp);
<App ref={ref} />

createRef 源码分析:

import type {RefObject} from 'shared/ReactTypes';

// an immutable object with a single mutable value
export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  return refObject;
}

forwardRef 实现:

import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols';


export function forwardRef<Props, ElementType: React$ElementType>(
  render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {

  // render函数必须有两个参数
  const elementType = {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
  };
  return elementType;
}

常见问题:

1、为什么要用ref呢?
ref会指向组件的实例,绑定在dom上可以直接操作dom,例如聚焦input框;绑定在自定义组件上可以在顶部调用自定义组件的方法等。

参考文档:

https://zh-hans.reactjs.org/docs/forwarding-refs.html

留下回复