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 definedReact.forwardRef
Regular functions and class components do not receiveref
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 throughref
- The subcomponent gets
ref
and forwards theref
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
After clicking the "Get Basic Information" button:
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。