In simple terms, ref is used to get the attributes of real dom elements or component instances.
1. Create and access
The value of ref varies according to the type of node:
- When an
ref
attribute is used for an HTML element , the constructor uses theReact.createRef()
createdref
underlying DOM element as itscurrent
attribute. - When an
ref
attribute is used to customize a class component , theref
object receives the mounted instance of the component as itscurrent
attribute. - You cannot use
ref
attributes on function components because they have no instances. If you want to use it, special treatment is required
1.1 ref = string (deprecated)
class Cualculator extends React.Component {
add =() => {
let num1 = parseInt(this.refs.num1.value)
let num2 = parseInt(this.refs.num2.value)
let result = num1 +num2
this.refs.result.value = result
}
render() {
return (
<div>
<input ref="num1" />+<input ref="num2"/><button onClick={this.add}>=</button><input ref="result"/>
</div>
)
}
}
* num1: corresponds to the real dom num1
* num2: corresponds to the real dom num2
1.2 ref = function (not recommended)
class Cualculator extends React.Component {
add = () => {
let num1 = parseInt (this.num1.value)
let num2 = parseInt (this .num2.value)
let result = num1 + num2
this.result.value = result
}
// When the ref value is a function, this function will be executed after the virtual dom is converted to the real dom and you buy it. The parameter is the real dom
render () {
return (
<div>
<input ref = { instance => this . num1 = instance} /> + <input ref = { instance => this.num2 = instance} /> <button onClick = { this .add}> = </ button> <input ref = { instance => this.result = instance}/>
</div>
)
}
}
1.3 ref = React.createRef () (recommended)
The ref attribute created by React.createRef () has the following characteristics:
When ref is passed to render
the element in, the reference to the node can be accessed in the ref current
attribute.
- When an
ref
attribute is used for an HTML element , the constructor uses theReact.createRef()
createdref
underlying DOM element as itscurrent
attribute. - When an
ref
attribute is used to customize a class component , theref
object receives the mounted instance of the component as itscurrent
attribute. - You cannot use attributes on function components
ref
because they have no instances. If you want to use it, special treatment is required
1.3.1 Html element
class Cualculator extends React.Component {
constructor(){
super()
this.num1 = React.createRef() //{current:null} current在虚拟dom转为真实dom插入页面之后变成真实dom
this.num2 = React.createRef() //{current:null} current在虚拟dom转为真实dom插入页面之后变成真实dom
this.result = React.createRef() //{current:null} current在虚拟dom转为真实dom插入页面之后变成真实dom
}
add =() => {
let num1 = parseInt(this.num1.current.value)
let num2 = parseInt(this.num2.current.value)
let result = num1 +num2
this.result.current.value = result
}
//ref值是一个函数的时候,此函数会在虚拟dom转为真实dom插入页面之后执行,参数就是真实dom
render() {
return (
<div>
<input ref={this.num1} />+<input ref={this.num2}/>
<button onClick={this.add}>=</button>
<input ref={this.result}/>
</div>
)
}
}
ReactDOM.render(<Cualculator></Cualculator>,document.getElementById('root'))
dom元素作为current属性的值
1.3.2 class组件
class UserName extends React.Component{
constructor(){
super()
this.inputRef = React.createRef()
}
render(){
return (
<input ref={this.inputRef}></input>
)
}
}
class Form extends React.Component{
constructor(){
super()
this.username = React.createRef() //this.username 就是UserName组件的实例 this.username.current = new UserName()
}
getFocus = () => {
this.username.current.inputRef.current.focus() //this.username.current.inputRef.current 获取到组件对应的真实dom节点 就是 input框
}
render(){
return (
<form>
<UserName ref={this.username}/>
<button type="button" onClick={this.getFocus}>让用户名获得焦点</button>
</form>
)
}
}
组件的实例等于current属性的值
1.3.3 函数组件
ref React.createRef()会获取到一个真实dom或者是一个组件实例对象 但是函数组件没有实例,那怎么获取函数组件的ref属性,这个时候就需要特殊处理
function UserName(props,ref) {
return <input ref={ref}></input>
}
const ForwordUsername = React.forwardRef(UserName)
class Form extends React.Component{
constructor(){
super()
this.username = React.createRef() //this.username 就是ForwordUsername组件的实例 this.username.current = new ForwordUsername()
}
getFocus = () => {
this.username.current.focus() //this.username.current.inputRef.current 获取到组件对应的真实dom节点 就是 input框
}
render(){
return (
<form>
<ForwordUsername ref={this.username}/>
<button type="button" onClick={this.getFocus}>让用户名获得焦点</button>
</form>
)
}
}
React.forwardRef会穿透UserName组件,获取到input的真实dom元素。
1.4 React.forwardRef()的底层实现
function UserName(props,ref) {
return <input ref={ref}></input>
}
function forwardRef (functionComponent) {
return class extends React.Component {
render() {
return functionComponent(this.props,this.props.ref2)
}
}
}
const ForwordUsername = forwardRef(UserName) //React.forwardRef返回一个类组件,将这个类组件传给
class Form extends React.Component{
constructor(){
super()
this.username = React.createRef() //this.username 就是UserName组件的实例 this.username.current = new UserName()
}
getFocus = () => {
this.username.current.focus() //this.username.current.inputRef.current 获取到组件对应的真实dom节点 就是 input框
}
render(){
return (
<form>
<ForwordUsername ref2={this.username}/>
<button type="button" onClick={this.getFocus}>让用户名获得焦点</button>
</form>
)
}
}
它是将函数组件转换成了类组件,当然也可以直接返回一个转化之后的函数组件
function UserName(props) {
return <input ref={props.ref2}></input>
}
//函数组件没有this,可以通过
function forwardRef (functionComponent) {
return props => functionComponent(props,props.ref2)
}
const ForwordUsername = forwardRef(UserName) //React.forwardRef返回一个类组件,将这个类组件传给
class Form extends React.Component{
constructor(){
super()
this.username = React.createRef() //this.username 就是UserName组件的实例 this.username.current = new UserName()
}
getFocus = () => {
this.username.current.focus() //this.username.current.inputRef.current 获取到组件对应的真实dom节点 就是 input框
}
render(){
return (
<form>
<ForwordUsername ref2={this.username}/>
<button type="button" onClick={this.getFocus}>让用户名获得焦点</button>
</form>
)
}
}
ReactDOM.render(<Form></Form>,document.getElementById('root'))
1.5 Refs 使用场景
- 处理焦点、文本选择或者媒体的控制
- 触发必要的动画
- 集成第三方 DOM 库