react ref
ref 主要在于提供父组件能直接操作子组件的能力,这里子组件可能是 dom 元素也可能是 react 组件的实例,不同于 props 形式的操作子组件,ref 可以直接调用子组件实例上的方法或属性。下面介绍了一些常用的用法:
什么时候使用 ref
- 用来操作原始 dom 元素的,获取尺寸、获取焦点等
- 触发命令式的动画
- 用来整合第三方 dom 库
创建 ref 有以下两种方式
- createRef
- callback ref
React 16.3 之后版本推荐使用 createRef 或 useRef 方式创建,React 16.3 以前版本使用 callback ref 方式
ref 的用在不同类型节点上有不同的值
- ref 属性用在 html dom 上,获取的值是 dom 对象
- ref 属性用在自定义类组件上,获取的值是组件的实例
- ref 属性不能用在函数组件上的,但可以通过 forwardRef 或 自定义属性传递 ref
使用场景
父组件 | 子组件 |
---|---|
函数组件 | 类组件 |
函数组件 | 函数组件 |
函数组件 | dom 元素 |
父组件是类组件的时候是相同的
createRef 在 dom 元素上
- 通过 useRef hook 或 createRef 创建 ref 对象
- 直接用在 dom 元素的 ref 属性上
- 获取的值绑定在 ref 的 current 属性上
- 获取的是 dom 对象,可以直接操作 dom 的属性和方法
import React, { useEffect, useRef } from "react";
const RefInDomElement = () => {
// 和使用 React.createRef() 一样
const avatarRef = useRef()
useEffect(() => {
console.log(avatarRef.current.src)
}, [])
return(
<img src="http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle" alt="" ref={avatarRef} />
)
}
export default RefInDomElement
createRef 用在自定义类组件上
- 通过 useRef hook 或 createRef 创建 ref 对象
- 直接用在自定义类组件的 ref 属性上
- 获取的值绑定在 ref 的 current 属性上
- 获取的是子组件的实例,可以直接调用子组件公开的属性和方法
import React, { useEffect, useRef } from "react";
const RefInCustomComponent = () => {
const caRef = useRef()
useEffect(() => {
console.log(caRef.current.setState({a: 1}))
}, [])
return(
<CustomAvatar ref={caRef} />
)
}
export default RefInCustomComponent
class CustomAvatar extends React.Component {
render() {
return(
<img src="http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle" alt="" />
)
}
}
createRef 用在自定义函数组件上
- 通过 useRef hook 或 createRef 创建 ref 对象
- 获取的值绑定在 ref 的 current 属性上
- 直接用在子组件的 ref 属性上,但子组件必须使用 forwardRef 包裹
- 子组件里的 ref 要绑定在下一级的 dom 元素或子组件上
- 获取的值取决于子组件里 ref 的使用
import React, { forwardRef, useEffect, useRef } from "react";
const RefInFunctionComponent = () => {
let avatarRef = useRef()
useEffect(() => {
console.log(avatarRef.current.src)
}, [])
return (
<FAvatar ref={avatarRef} />
// 可以使用自定义属性传递 ref
// <Avatar someRef={avatarRef} />
)
}
export default RefInFunctionComponent
const avatar_URL = 'http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle'
const FAvatar = forwardRef(({}, ref) => {
return(
<img src={avatar_URL} alt="" ref={ref} />
)
})
const Avatar = ({ someRef }) => {
return(
<img src={avatar_URL} alt="" ref={someRef} />
)
}
callback ref 用在 dom 元素上
- 在 ref 属性上绑定 fn 类型的值
- ref 不会有 current 属性
- 直接用在 dom 的 ref 属性上
- 获取的是 dom 对象,可以直接操作 dom 的属性和方法
import React, { useEffect } from "react";
// callback ref in html dom element
const CallbackRefInDomElement = () => {
let avatarRef = null
useEffect(() => {
console.log(avatarRef)
}, [])
return (
<img src={avatar_URL} alt="" ref={ref => avatarRef = ref} />
)
}
export default CallbackRefInDomElement
const avatar_URL = 'http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle'
callback ref 用在自定义类组件上
- 在 ref 属性上绑定 fn 类型的值
- ref 不会有 current 属性
- 直接用在子组件的 ref 属性上
- 获取的是子组件的实例
import React, { forwardRef, useEffect } from "react";
const CallbackRefInCustomComponent = () => {
let avatarRef = null
useEffect(() => {
console.log(avatarRef)
}, [])
return (
<CAvatar ref={ref => avatarRef = ref} />
)
}
export default CallbackRefInCustomComponent
const avatar_URL = 'http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle'
class CAvatar extends React.Component {
render() {
return(
<img src={avatar_URL} alt="" />
)
}
}
callback ref 用在函数组件上
- 在 ref 属性上绑定 fn 类型的值
- ref 不会有 current 属性
- 直接用在子组件的 ref 属性上,但子组件必须使用 forwardRef 包裹
- 子组件里的 ref 要绑定在下一级的 dom 元素或子组件上
- 获取的值取决于子组件里 ref 的使用
- 也可以通过自定义属性传递 ref,脱离 forwardRef
import React, { forwardRef, useEffect } from "react";
// 函数组件里使用 callback ref
const CallbackRefInFunctionComponent = () => {
let avatarRef = null
useEffect(() => {
console.log(avatarRef)
}, [])
return (
<FAvatar ref={ref => avatarRef = ref} />
// 可以使用自定义属性传递 ref
// <Avatar someRef={ref => avatarRef = ref} />
)
}
export default CallbackRefInFunctionComponent
const avatar_URL = 'http://file04.shouwuapp.com/1/202201/f2254b0777b8483b47bad13e357dd099.jpg?x-oss-process=style/middle'
const Avatar = ({ someRef }) => {
return(
<img src={avatar_URL} alt="" ref={someRef} />
)
}
const FAvatar = forwardRef(({}, ref) => {
return(
<img src={avatar_URL} alt="" ref={ref} />
)
})