1. What is refs?

  • Refs provides a way to access DOM nodes or React elements created in the Render method;
  • Official note: In a typical React data flow, props is the only way for the parent to interact with its children. To modify a child component, you need to re-render it using new props. However, in some cases, you need to force changes to subcomponents outside of the typical data flow. The child component being modified may be an instance of the React component or a DOM element. React offers solutions in both cases.
  • In layman’s terms, it provides a bridge for a parent component to access data or methods in a child component

2. The refs

2.1 Use refs in Class components (parent and child components are classes)

Get DOM node

import { Button } from 'antd'; export default class RefClass extends Component { constructor(props){ super(props) this.myRef = createRef() this.changeInput = this.changeInput.bind(this); } changeInput(){ console.log('this.myRef',this.myRef.current) console.log('this.myRef',this.myRef.current.value) } render() { return ( <div > RefClass <input ref={this.myRef} /> <Button type="primary" onClick={this.changeInput}> Submit  </Button> </div> ) } }Copy the code

The parent component accesses data and methods in the child component

The parent component

import Child from './Child' import { Button } from 'antd'; export default class RefClass extends Component { constructor(props){ super(props) this.myRef = createRef() this.changeInput = this.changeInput.bind(this); } changeInput enclosing childRef = createRef () () {the console. The log (this) childRef). The current state. The name) / / call the method that child components this.childRef.current.updateState(this.myRef.current.value) } render() { return ( <div > RefClass <input ref={this.myRef} /> <Child ref={this.childRef} /> <Button type="primary" onClick={this.changeInput}> Submit </Button> </div> ) } }Copy the code

Child components

import React, { Component } from 'react' export default class Child extends Component { constructor(props){ super(props) this.state={ {this.setState({name: MSG})} render() {return (<div> {this.state-name} </div>)} }Copy the code

Use of refs in middle age (both parent and child components are hooks)

Get the DOM element

import { Button } from 'antd';

const RefHooks = () => {
  const childRef = useRef(null)
  const  changeInput = ()=>{
    console.log('changeInput',childRef.current.value)
  }

  return (
    <div>
      <div>RefHooks</div>
      <input ref={childRef} />
      <Button type="primary" onClick={changeInput}>
        Submit
      </Button>
    </div>
  )
}

export default RefHooks
Copy the code

Methods or data that a parent component accesses to a child component

UseImperativeHandle is introduced to expose data and methods that use the ref parent to access child components, and useImperativeHandle should use the parent with the forwardRef

import { Button } from 'antd'; import Child from './Child' const RefHooks = () => { const inputRef = useRef(null) const childRef = useRef(null) const ChangeInput = () = > {the console. The log (' changeInput 'inputRef. Current. The value) childRef. Current. ChangText (' I'm a parent component modified child components')} return  ( <div> <div>RefHooks</div> <input ref={inputRef} /> <Child ref={childRef}/> <Button type="primary" onClick={changeInput}> Submit </Button> </div> ) } export default RefHooksCopy the code

Child components

const Child = (props,ref) => { const [state, Setstate] = useState(' I am a child ') const changText = (e)=>{setState (e)} useImperativeHandle(ref, () => ({changText})); return ( <div> {state} </div> ) } export default forwardRef(Child)Copy the code

Note:

  • Child components to useforwardRefTo wrap,useImperativeHandleThe method is exposed only to the parent component, the component itself cannot be called, both want to use, as shown above;
  • When a child component accepts a REF, it also accepts props; otherwise, an error is reported

2.3 Use of refs in higher-order components

Calss High order component type

Define a ref to be aliased into a HOC component, and add the ref to the component exported in the call to HOC

The parent component

import { Button } from 'antd'
import HocIndex from './HocIndex'
import User from './User'

const HocUser = HocIndex(User);
export default class RefHOC extends Component {
  constructor(props) {
    super(props)
    this.classHocRef = createRef(null)
    this.inputRef = createRef(null)
    this.handClick = this.handClick.bind(this)
  }

  handClick(){
    this.classHocRef.current.updatFn(this.inputRef.current.value)
  }

  render() {
    return (
      <div>
        <HocUser name={'name'} refText={this.classHocRef} />
        <input ref={this.inputRef} />
        <Button type="primary" onClick={this.handClick}>
          Submit
        </Button>
      </div>
    )
  }
}
Copy the code

High order component

function HocIndex(WrappedComponent) { return class WrappingComponent extends React.Component { render() { const props = {... this.props,ref:this.props.refText} return ( <WrappedComponent {... props} /> ) } } } export default HocIndex;Copy the code

Child components

Export Default class User extends Component {constructor(props){super(props) this.state={name:' I am a Hoc Component '}} updatFn(e){ this.setState({ name:e }) } render() { return ( <div>{this.state.name}</div> ) } }Copy the code

Hooks high-level component types

The parent component

import React, { useRef } from 'react' import HooksUser from './HooksUser'; import { Button } from 'antd' const Index = () => { const hocRef = useRef(null); Const changeInput=()=>{hocref.current. ChangText (' Parent modifs child ')} return (<div> I am hooks component <HooksUser ref={hocRef}) name='user' /> <div> <Button type="primary" onClick={changeInput}> Submit </Button> </div> </div> ) } export default IndexCopy the code

High order component

import React,{forwardRef} from 'react' const HookHoc = Component => { const HocIndex = ({hocRef,... props})=> <Component ref={hocRef} {... props} /> return forwardRef((props,ref)=> <HocIndex {... props} hocRef={ref}/>) } export default HookHocCopy the code

Child components

Import HookHoc from './HookHoc' const HooksUser = (props,ref) => {const [state, setstate] = useState(' I am a child of hooks '); const changText = (e)=>{ setstate(e) } useImperativeHandle(ref, () => ({ changText })); return ( <div> {state} </div> ) } export default HookHoc(forwardRef(HooksUser))Copy the code

2.4 Setting refs callback Mode

  • More accurate control of when refs are set and released
  • ReactIs called when the component is mountedrefThe callback function is passed inDOM elements(Or React instance), which is called when uninstalling and passed null. incomponentDidMountcomponentDidUpdateReact ensures Refs are up to date before triggering.
  • Refs in the form of callbacks can be passed between components.

Class type component

import { Button } from 'antd' export default class index extends Component { constructor(props) { super(props); this.textInput = null; this.setTextInputRef = element => { this.textInput = element; }; this.focusTextInput = () => { if (this.textInput) this.textInput.focus(); console.log('this.textInput',this.textInput.value) }; } componentDidMount() { this.focusTextInput(); } render() { return ( <div> <input type="text" ref={this.setTextInputRef} /> <Button type="primary" onClick={this.focusTextInput}> Submit </Button> </div> ); }}Copy the code

Hooks component

import { Button } from 'antd';
import React, { useEffect } from 'react';

function MyInput(props) {
  return (
    <input type="text" ref={props.inputRef} />
  )
}

const HooksFnRef = () => {
  let ref = null;
  useEffect(() => {
    ref.focus();
    console.log('ref', ref)
  }, [ref]);
  const getInputVlaue = () => {
    console.log(ref.value)
  }
  return (
    <div>
      <MyInput inputRef={ele => ref = ele} />
      <Button type="primary" onClick={getInputVlaue}>
        Submit
      </Button>
    </div>
  )
}

export default HooksFnRef
Copy the code

3. A pothole encountered in refs

The refs callback exists if the ref callback is defined as an inline function, it will be executed twice during the update process, passing in null the first time, and then the DOM element the second time. This is because a new function instance is created each time it renders, so React clears the old ref and sets the new one. This can be avoided by defining the ref callback function as a class binding function, but in most cases it is irrelevant.

4. To summarize

  • The component does not render when the ref content changes; You can call the method of the subcomponent to realize the required subcomponent to update, reduce the rendering of the rest of the components;
  • If you run some code when binding or unbinding the REF of a DOM node, you need to use the ref callback
  • The abuse of Refs is not officially recommended and the use of refs in the project should be minimized

If there is a problem to write welcome friends directly pointed out. In this grateful not into;