React hooks--useRef
系列 -
目录
注意
本文最后更新于 2023-07-26,文中内容可能已过时。
useRef
const ref = useRef(initialValue)
ref
就是引用,vue 中也有类似的概念,在 react 中 ref 是一个形如 {current: initialValue}
的对象,不仅可以用来操作 DOM,也可以承载数据。
与 useState 的区别
既然能承载数据,那么和 useState
有什么渊源呢?让我们看看官网的一句话:useRef is a React Hook that lets you reference a value that’s not needed for rendering.
,重点在后半句,大概意思就是引用了一个与渲染无关的值。
在承载数据方面,这就是与 useState
最大的区别:
useRef
引用的数据在改变后不会影响组件渲染,类似于函数组件的一个实例属性useState
的值改变后会引发重新渲染
函数式组件在每次渲染中的 props、state 等等都是那次渲染中所独有的,当需要在 useEffect 中访问
未来
的 props/state 时,可以使用 useRef 。Demo: 随意输入并 send 后,再次输入,获取的是全部的输入。
TS 环境下的使用
在 TS 环境下,往往你可能会遇到此类报错:
Type '{ ref: RefObject<never>; }' is not assignable to type 'IntrinsicAttributes'. Property 'ref' does not exist on type 'IntrinsicAttributes'.ts(2322)
这就需要做一定的类型处理了。
前置先介绍两个 api:
- 因为函数不能直接接收 ref,所以在子组件中使用
forwardRef
这个 api 来传递进子组件。在类组件时代也常用来跨祖孙组件传递 ref, 比如 HOC。 - 父组件想要访问子组件的数据,需要使用
useImperativeHandle
这个 api 对外暴露。
// 父组件
const Demo: FC = () => {
// 给自定义组件添加 ref,需要使用 ElementRef<typeof 组件> 来获取 ref 的类型
const SonRef = useRef<ElementRef<typeof Son>>(null)
const handleClick = () => {
SonRef.current?.test()
}
return (
<>
<Son ref={SonRef}></Son>
<button onClick={() => handleClick()}>click</button>
</>
)
}
// 子组件 两种方式设置 ref 类型
// 1. 用泛型,注意与参数的位置是相反的
const Son = forwardRef<typeRef, {}>((props, ref) => {
useImperativeHandle(ref, () => {
return {
test: () => console.log('hello world')
}
})
return (
<>
<div> hello world</div>
</>
)
})
// 2. 在参数中使用 Ref
// const Son = forwardRef((props, ref: Ref<typeRef>) => {})