3

In a typical React data flow, props are the only way for parent and child components to interact. To modify a child component, you need to re-render it with new props. However, in some cases, it is necessary to actively view or forcibly modify the child components outside of the typical data flow. At this time, Refs need to be used to expose the DOM Refs to the parent component.

When to use Refs

Here are a few situations where refs are suitable:

  • Manage focus, text selection or media playback;
  • Trigger forced animation;
  • Integrate third-party DOM libraries;
  • Measure the size or position of the child DOM node;
Avoid using refs to do anything that can be done through declarative implementation, because it will break the encapsulation of the component.

Refs and components

By default, the ref attribute must point to a DOM element or class component. cannot use the ref attribute on function components because they have no instances. If you need to use ref in a function component, you can use forwardRef , or convert the component to a class component.

React.forwardRef

React.forwardRef(props, ref)

  • The second parameter ref only exists when the component is defined React.forwardRef Regular functions and class components do not receive ref ref does not exist in props.
  • Ref forwarding is not limited to DOM components, it can also forward refs to class component instances.

Ref forward

If you use React version 16.3 or higher, use ref forwarding to expose DOM Refs to the parent component. Ref forwarding allows the component to expose the ref sub-component just like exposing its own ref. If you don't have control over the implementation of findDOMNode() , you can only use 061a09b13e1e53, but it has been deprecated in strict mode and is not recommended.

Realize Ref forwarding method:

  • ref and forwardRef
  • useImperativeHandle and forwardRef

ref and forwardRef

  • The parent component creates ref and passes it down to the child component
  • The child component forwardRef passed to it through ref
  • The subcomponent gets ref and forwards the ref to one of its own elements
  • The parent component obtains the bound DOM element instance ref.current

Disadvantages

  • Will directly expose the DOM bound to the ref element to the parent component
  • After the parent component gets the DOM, it can perform arbitrary operations

example

The following example uses the useRef Hook introduced in React 16.6, if it is React 16.3 version, use React.createRef() API, if it is an earlier version, use callback form refs .

// 子组件
import React, { forwardRef, useState } from 'react'

const BaseInfo = forwardRef((props, ref) => {
  console.log('BaseInfo --- props', props)
  console.log('BaseInfo --- ref', ref)

  const [name, setName] = useState('')
  const [age, setAge] = useState('')

  return (
    <div ref={ref}>
      姓名:
      <input onChange={val => setName(val)} />
      年龄:
      <input onChange={val => setAge(val)} />
    </div>
  )
})
// 父组件
import React, { useRef } from 'react'
import BaseInfo from './BaseInfo'

function RefTest() {
  const baseInfoRef = useRef(null)

  const getBaseInfo = () => {
    console.log('getBaseInfo --- baseInfoRef', baseInfoRef.current)
  }

  return (
    <>
      <BaseInfo
        dataSource={{ name: '混沌' }}
        ref={baseInfoRef}
      />
      <button onClick={getBaseInfo}>获取基本信息</button>
    </>
  )
}

output

image-20211122112817260.png
After clicking the "Get Basic Information" button:
image-20211122112901116.png

useImperativeHandle and forwardRef

Introduction to useImperativeHandle

useImperativeHandle(ref, createHandle, [deps])

When using ref , customize the instance value exposed to the parent component useImperativeHandle

Through useImperativeHandle, the ref passed by the parent component and the object returned by the second parameter of useImperativeHandle are bound together.

Advantages

  • Only expose the DOM methods needed by the parent component;
  • In the parent component, when xxxRef.current is called, the object is returned;

example

// 子组件
const OtherInfo = (props, ref) => {
  console.log('OtherInfo --- props', props)
  console.log('OtherInfo --- ref', ref)

  const inputRef = useRef()
  const [school, setSchool] = useState('')

  useImperativeHandle(ref, () => {
    console.log('useImperativeHandle --- ref', ref)
    return ({
      focus: () => {
        inputRef.current.focus()
      },
      getSchool: () => {
        return inputRef.current.value
      }
    })
  }, [inputRef])

  return (
    <div>
      学校:
      <input ref={inputRef} onChange={val => setSchool(val)}/>
    </div>
  )
}

export default forwardRef(OtherInfo)
// 父组件
import React, { useRef } from 'react'
import OtherInfo from './OtherInfo'

function RefTest() {
  const otherInfoRef = useRef(null)

  const getOtherInfo = () => {
    console.log('getOtherInfo --- otherInfoRef', otherInfoRef.current)
    console.log('getOtherInfo --- otherInfoRef --- getSchool', otherInfoRef.current.getSchool())
  }

  return (
    <>
      <OtherInfo
        dataSource={{ school: '大学' }}
        ref={otherInfoRef}
      />
      <button onClick={getOtherInfo}>获取其他信息</button>
    </>
  )
}

output
image-20211122140641074.png


时倾
794 声望2.4k 粉丝

把梦想放在心中