use

Manipulate attributes of components, subcomponents, and elements

In a typical React top-down data flow, props is the only way for the parent and child to interact, and to modify a child component, you need to re-render it using the new props. In some cases, however, you need to force changes to child components and retrieve component properties outside of a typical data flow. The child component being modified may be an instance of the React component or a native HTML element.

Common scenarios:

  1. How do I get native in a componentHTMLElement attributes, methods?
  2. How do I get attributes and methods of child components from parent components?
  3. How do I get a native from a child component directly from a parent componentHTMLElement?

There are four ways to create a Ref

React.createRef()

In React 16.3 and later, you can use the React.createref () method in the instance constructor to create a ref and assign it to the custom properties of the instance object so that it can be used throughout the component, It is then appended to the ref attribute of a native HTML element or a Class component.

class MyComponent extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); } render() { return <div ref={this.myRef} />; }}Copy the code

Callback function mode

React also supports another way to set a REF, called a “callback ref.” It gives you more fine-grained control over when refs are set and released.

Unlike the ref attribute created through createRef(), “callback refs” passes a function that takes an instance object of the component or a native HTML DOM object as a parameter and assigns that parameter to a custom property of the component instance object so that it can be used throughout the component.

class MyComponent extends React.Component { constructor(props) { super(props); this.setMyRef = null; } render() { return < div ref={ (el) => this.setMyRef = el } />; }}Copy the code

React calls the refS callback when a component is mounted and passes in a parameter object. It calls the refs callback again when a component is unmounted and passes in null as a parameter.

The parent component can directly manipulate the attributes of an element in a child component by using a callback function, as described below:

String mode (obsolete, not recommended)

Set the ref attribute directly to a string, obtained through this.refs

 const element = <div ref="myRef">string ref</div>
 const node = this.refs.myRef
Copy the code

The use of string refs is outdated and problematic

  1. Need to beReactKeeping track of currently rendered components is a bit of a drag on performance
  2. When usingrender callbackSet for child components when rendering component content in Render Prop moderefNot available in the parent component, which is misleading.
Class MyComponent extends Component {renderRow = () => {// String ref is bound to the child DataTable instead of the parent MyComponent return <input ref="input" />; Render () {return <DataTable renderRow={this.renderrow} />}} // render() {return <DataTable renderRow={this.renderrow} />}} // render() {render() {return <DataTable renderRow={this.renderrow} />}} // render() {render() {return <DataTable renderRow={this.renderrow} />}} // // This problem can be avoided by setting the callback function,Copy the code

React.useRef()

In React 16.8 and later, we introduced Hooks to set the ref attribute for React elements. Since Hooks can only be used on function components, useRef() can only set the ref attribute for elements in function components.

 function FocusInput() {
   const inputEl = useRef();
   //inputEl.current.focus();
   return (
     <>
       <input ref={inputEl} type="text" />
     </>
   );
 }
Copy the code

CreateRef () is different from useRef()

 //useRef() 
 const inputEl = useRef();
 <input ref={inputEl} type="text" />

 //createRef()
 const inputEl = createRef();
 <input ref={inputEl} type="text" />
Copy the code

The React internal method is called and the ref attribute is assigned to an element inside the component. Both methods seem to be used in function components. Why does React have a new API for creating refs?

UseRef returns a mutable ref object whose.current property is initialized as the passed parameter (initialValue). The ref object returned persists throughout the life of the component.

Refs are created using react.createref () and attached to the React element via the ref attribute. When components are constructed, refs are typically assigned to instance properties so that they can be referenced throughout the component.

Creating a ref in both ways in a function component is an example of how to create a ref in both ways

function MyComponent() { console.log("------------------------render--------------------------") const [count, setCount] = useState(0); const createRef = React.createRef(); const useRef = React.useRef(); console.log("createRef", createRef, "useRef",useRef) if (! createRef.current) { createRef.current = count; } if (! useRef.current) { useRef.current = count; } console.log("createRef", createRef, "useRef",useRef) return ( <div> <h3>count: {count}</h3> <button onClick={() => setCount(count + 1)}>add button</button> </div> ); }Copy the code

In the above function component, each state change causes the code within the function to be re-executed; We also know that the ref attribute attached to the element will eventually be reflected in its.current attribute, so will the printed value be different every time the count state changes?

CreateRef generates a new object every time the component is re-rendered, so it does not save the previous current property value; UseRef creates the same object all its life, or operates on the memory address of the same object all its life.

Ref to forward

Going back to the three questions raised at the beginning, the first two scenarios can be directly accessed by setting the ref for the corresponding element or component; So the third question is, how do YOU get native HTML elements in child components directly from the parent component?

Unlike the props property of a component, the ref set in the parent component is not passed through. Instead, it is treated like a key when received by React and does not appear in the props object of a child component: A ref set to a subcomponent is only attached to the current subcomponent, not passed down, and the.current property of the ref object is used to obtain the instance object of the subcomponent. There are currently two ways:

  1. The callback ref

     function Child(props) {
       return (
         <input ref={props.childRef} />
       );
     }
     ​
     class MyComponent extends Component {
       handleClick() {
         this.childRef.
         console.dir(this.childRef)
       }
       render () {
         return (
           <div>
             <Child childRef={el => this.childRef = el }></Child>
             <p onClick={() => this.handleClick()}>MyComponent</p>
           </div>
         );
       }
     }
     ​
    Copy the code

    For example, if you set a generic childRef property to the Child component in the parent MyComponent, then inside the Child component you can get props. ChildRef. this.childRef = el} /> and this represents the parent component. This callback is called when the Child component is mounted. We pass the DOM object of the input element as a parameter to the callback function, so that the parent component can directly manipulate the attributes of an HTML element inside the child component. A very clever use of function closures makes the connection between the two. You can’t do this with strings, so this is one of the reasons why strings are not recommended.

  2. Ref to forward

const Child = React.forwardRef((props, ref) => { return <input ref={ref} defaultValue={props.defaultValue} /> } ) class MyComponent extends React.Component{ constructor(props) { super(props) this.childRef = React.createRef() } focus() { this.childRef.current.focus() } render () { return ( <div> <Child defaultValue={'ref'} ref={this.childRef}></Child> <button onClick={() => this.focus()}>focus</button> </div> ); }}Copy the code

The react.forwardref ()API is used to forward the ref attribute automatically to its child elements. React.forwardref () takes a function whose second argument receives the component’s ref property and can be passed down;