The ref gets an instance. It can be a DOM instance or a ClassComponent instance.

If the target FunctionComponent is a PureComponent, there is no instance (ref). If the target FunctionComponent is a FunctionComponent, there is no instance (ref).

If you are a library developer, the user does not know the library component class. If the FunctionComponent class is FunctionComponent and the user wants to retrieve the library component, what do you do?

(3) The connect method in Redux wraps a component as a high-level component (HOC), so how can I get a wrapped component instance through ref?

4 Props cannot pass ref

React also specifies the conditions for using ref:

The react. forwardRef is there to solve these problems.

React.forwardRef

Zh-hans.reactjs.org/docs/react-…

React.forwardRef (forwardRef

ForwardRef creates a React component that forwards the ref properties it receives to an internal component

Source:

export default function forwardRef<Props.ElementTypeReact$ElementType> (

  render: (props: Props, ref: React$Ref<ElementType>
) = >React$Node.

{

  // Delete dev code



  return {

    // After the forwardRef wraps the component? Typeof is REACT_FORWARD_REF_TYPE

    ?typeof: REACT_FORWARD_REF_TYPE,

    //render is the FunctionComponent wrapper, ClassComponent is not forwardRef

    render,

  };

}

Copy the code

(1) return an object, Child:

const Child = React.forwardRef((props, ref) = > (

  <button ref={ref}>

    {props.children}

  </button>


));



console.log(Child,'Child29')

Copy the code

(2) Return? Typeof, which does not indicate that the Child component type is REACT_FORWARD_REF_TYPE

React.createelement () and ReactElement() ReactElement type: REACT_ELEMENT_TYPE

const ReactElement = function(type, key, ref, self, source, owner, props{

  const element = {

    // This tag allows us to uniquely identify this as a React Element

    // Identify the type of element

    // Since JSX is created with createElement, ReactElement is of a fixed type: REACT_ELEMENT_TYPE

    / / important! Because react, when it finally renders to the DOM, you have to decide, okay? typeof===REACT_ELEMENT_TYPE

    ?typeof: REACT_ELEMENT_TYPE,



    // Built-in properties that belong on the element

    // Sets the built-in attributes of the element

    type: type,



  };

}

Copy the code

Note: the variable Child is an object:

{

    $$typeof: REACT_FORWARD_REF_TYPE,

    render,

  };

Copy the code

The Child component is a ReactElement object, which is different:

  const element = {

    $$typeof: REACT_ELEMENT_TYPE,

    typetype.

  };

Copy the code

When a Child is converted to ReactElement, the Child object is used as the type property of the Child component:

  const element = {

    ?typeof: REACT_ELEMENT_TYPE,

    // Attention!!

    type: {

      ?typeof: REACT_FORWARD_REF_TYPE,

      render,

    },

  };

Copy the code

Do not think React component is wrapped by forwardRef? The value of typeof is changed to REACT_FORWARD_REF_TYPE!

The forwardRef is only available for FunctionComponent, not ClassComponent

Update the FunctionComponent that the ref points to and is wrapped by the react. forwardRef

Source:

// Update FunctionComponent wrapped by react. forwardRef

function updateForwardRef(

  current: Fiber | null.

  workInProgress: Fiber,

  Component: any,

  nextProps: any,

  renderExpirationTime: ExpirationTime,

{

  // TODO: current can be non-null here even if the component

  // hasn't yet mounted. This happens after the first render suspends.

  // We'll need to figure out if this is fine or can cause issues.



  // Delete dev code



  //Component:{

  / /? typeof: REACT_FORWARD_REF_TYPE,

  // render,

  // }



  //FunctionComponent

  const render = Component.render;

  // FunctionComponent is not allowed at the development level, but if you print props,

  // React only allows internal ref passes through props

  const ref = workInProgress.ref;



  // The rest is a fork of updateFunctionComponent

  let nextChildren;

  // Context related can be skipped

  prepareToReadContext(workInProgress, renderExpirationTime);

  prepareToReadEventComponents(workInProgress);

  if (__DEV__) {

    // Delete dev code

  } else {

    // Perform some operations on the hook functions used in the rendering process

    / / about renderWithHooks's explanation, please see: https://www.jianshu.com/p/959498695e83



    // Note that the argument passed in updateFunctionComponent() is not ref,

    // Instead of context: nextChildren = renderWithHooks(

    // current,

    // workInProgress,

    // Component,

    // nextProps,

    // Pass context instead of ref

    // context,

    // renderExpirationTime,

    // );

    nextChildren = renderWithHooks(

      current,

      workInProgress,

      render,

      nextProps,

      ref.

      renderExpirationTime,

    );

    //renderWithHooks update ref or context internally by let children = Component(props, refOrContext)

  }



  // If the props are the same and the ref is the same, no update is needed

  if(current ! = =null && !didReceiveUpdate) {

    // Skip the hooks update

    / / about bailoutHooks's explanation, please see: https://www.jianshu.com/p/959498695e83

    bailoutHooks(current, workInProgress, renderExpirationTime);

    // Skip the update of this node and all its children

    / / about bailoutOnAlreadyFinishedWork's explanation, please see: https://www.jianshu.com/p/06b18db8b5d4

    return bailoutOnAlreadyFinishedWork(

      current,

      workInProgress,

      renderExpirationTime,

    );

  }



  // React DevTools reads this flag.

  workInProgress.effectTag |= PerformedWork;

  // Change the ReactElement into a fiber object and update it to generate the corresponding DOM instance and mount it to the real DOM node

  / / about reconcileChildren's explanation, please see: https://www.jianshu.com/p/959498695e83

  reconcileChildren(

    current,

    workInProgress,

    nextChildren,

    renderExpirationTime,

  );

  return workInProgress.child;

}

Copy the code

For the reconcileChildren, see renderWithHooks, bailoutHooks, and reconcileChildren. React FunctionComponent

(2) about the interpretation of bailoutOnAlreadyFinishedWork, see: the React workLoop source code parsing

(2) The ref update is in renderWithHooks:

let children = Component(props, refOrContext);

Copy the code

The FunctionComponent is the render property of the react. forwardRef Child, which executes the FunctionComponent

RefOrContext in this case is workinProgress.ref

Component(props, refOrContext) (props, ref)

React.forwardRef((props, ref)= > (

  xxx

));

Copy the code

(after)