React16.3 modifies Refs and provides Forwarding Refs for manipulating DOM nodes in child components in parent components. This article introduces the new Refs representation and Forwarding Refs.

Ref is the standard method of manipulating child components in the parent component, making it pass values outside of the parent component, and then updating the child component.

1. Refs in Act16.3

(1) Create

In version 16.3 Refs are created using the react.createref () method and associated with the ref attribute. For example, we create a Child component and use ref in this component:

class Child extends React.Component{ constructor(props){ super(props); this.myRef=React.createRef(); // create Ref in React16.3}render() {return <input ref={this.myRef}/>
  }
}Copy the code

React16.3 provides the current attribute to refer to the node after render:

  componentDidMount(){ console.log(this.myRef.current); //render the node to which the ref points}Copy the code

In addition, the same node that Ref points to can be either a DOM node or a class component.

(2) The node pointed to by the Ref attribute cannot be a function component

The component that ref points to cannot be a function component because the component we obtain from ref contains the declaration period and state.

function MyFunctionComponent(){
  return <div>1</div>
}
class Child extends React.Component{
  constructor(props){
    super(props);
    this.myRef=React.createRef();
  }
  render(){
    return <MyFunctionComponent ref={this.myRef}/>
    // Warning: Stateless function Components
    //cannot be given refs. Attempts to access this
    //ref will fail.}}Copy the code

In a function component, however, it is possible to point to a class component or dom node through a ref.

2. Expose the DOM node in the child component to the parent component

(1) Usage Scenarios In some scenarios, we may need to operate the DOM node of the component in a parent component, and the structure hierarchy is as follows:

Parent component — > child component — > DOM node in child component

This operation is not recommended because it may break the encapsulation of the component. Standard parent-child component communication is usually in the form of Props, but sometimes there is a need to operate dom nodes directly, for example, to make dom nodes focus. The parent component needs to know the location of a DOM node in the child component, and so on.

In this case, if we only add attribute ref to the parent component and reference to the child component, the ref only refers to the child component and does not know the DOM node in the child component. For example, the child component is:

class Child extends React.Component{
  constructor(props){
    super(props);
  }
  render() {return <input />
  }
}Copy the code

Parent component, ref:

class Father extends React.Component{
  constructor(props){
    super(props);
    this.myRef=React.createRef();
  }
  componentDidMount(){
    console.log(this.myRef.current);
  }
  render() {return <Child ref={this.myRef}/>
  }
}Copy the code

The output myRef is:

The Child {props: {... }, the context: {... }, refs: {... }, updater: {... }, _reactInternalFiber: FiberNode,... }Copy the code

That is, you point to the child component, not the DOM node in the child component.

Forwarding refs in React16.3

The Forwarding refs in Act16.3 makes it possible to obtain DOM nodes in child components in the parent component.

If you know that PS: DOM is an API for HTML and XML, you should know that it has some functionality that you can use to perform a series of dynamic operations on HTML pages.

Forwarding refs provides a React. ForwardRef component to create the component, and the React. ForwardRef method passes ref, which points to a specific DOM node. The specific pointing process is:

The parent myRef — > argument in the react. forwardRef — > ref — > in the child created by the forwardRef method points to a DOM node in the child

Example: Subcomponent (created through the forwardRef method)

const Child=React.forwardRef((props,ref)=>(
  <input ref={ref} />
));Copy the code

The parent component:

class Father extends React.Component{
  constructor(props){
    super(props);
    this.myRef=React.createRef();
  }
  componentDidMount(){
    console.log(this.myRef.current);
  }
  render() {return <Child ref={this.myRef}/>
  }
}Copy the code

The output of myRef is input

Let’s take a step-by-step look at how this process works.

First create a myRef in the Father component using the React createRef method

Pass myRef in the Child component by specifying ref={myRef}

In the constructor of the child component, the ref that is passed is accepted as an argument, and the ref of that argument can then be copied to the DOM node in the child component, etc.

After the parent component’s myRef is associated with the corresponding DOM node, the current property is used to get the child component’s DOM node in the parent component.

(3) Forwarding Refs in high-level component HOC Let’s create a simple HOC:

function logProps(WrappedComponent) {
  class logProps extends React.Component {
    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  return logProps;
}Copy the code

This HOC, used to build a new component, can output all the attribute information of the incoming component in the new component.

Let the Child component be:

class Child extends React.Component{
  constructor(props){
    super(props);
  }
  render() {return <input />
  }
}Copy the code

We generate a higher-order component based on the Child component via logProps:

const logProps=logProps(Child);Copy the code

Get child components from parent components by ref:

class Father extends React.Component{
  constructor(props){
    super(props);
    this.myRef=React.createRef();
  }
  componentDidMount(){
    console.log(this.myRef.current);
  }
  render() {return <LogProps ref={this.myRef}/>
  }
}Copy the code

The output is LogProps instead of Child, and the parent component’s myRef points to the ad-generated component.

LogProps {props: {... }, the context: {... }, refs: {... }, updater: {... }, _reactInternalFiber: FiberNode,... }Copy the code

Similarly, if we want myRef in the parent component to point to HOC’s original component, we need to rewrite HOC’s constructor:

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; // Assign the custom prop"forwardedRef" as a ref
      return<Component ref={forwardedRef} {... rest} />; } } // Note the second param"ref" provided by React.forwardRef.
  // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
  // And it can then be attached to the Component.
  return React.forwardRef((props, ref) => {
    return<LogProps {... props} forwardedRef={ref} />; }); } At this point, the output myRef is: ChildCopy the code

React.createref () does not abolish callbacks to create refs.