- 看到 ref 大家不管是在vue 中 还是在react 中都比较熟悉, vue3 的ref 有两个,vue2 有一个,但是ref 的作用都有一个公共的作用,那就是获取真实的dom。
- 在react 的类组件中,我们可以在类中定义属性 ref 详情, 但是在函数组件是不能直接使用 ref, 如果需要使用 ref 那么就只能是 ref 转发, 说实话这个函数组件的 ref 转发 是有点绕, 而且还会增加组件的层级。个人感觉不怎么友好。
语法
const refContainer = useRef(initialValue);
参数 initialValue: 初始值,可以传,也可以不传,如果参数传了那就是用来固定数据的引用,这个有点类似 vue3中的ref, 只是在这里的对象是{current: xxx} 而vue3 中的是 {value: xxxx}
- 返回值: 是一个{current:xxx}对象,里面绑定给 react 的内置组件,那current 是一个dom, 不绑定且有参数的话,那么就是一个 固定引用的数据
案例
绑定react 内置组件 获取dom
import React, { useCallback, useRef } from 'react' export default function TestRefHook() { // ref 对象 const inputRef = useRef<HTMLInputElement>(null) // 使用 callback 绑定函数引用,养成习惯 const handle= useCallback((e: React.ChangeEvent<HTMLInputElement> ) =>{ console.log(inputRef.current,'----===='); },[]) return ( <div> <input type="text" ref={inputRef} onChange={handle}/> </div> ) }
效果
ref 作用于react 内置组件,获取dom
ref 作用于组件
ref 只能直接作用于类组件,获取的是类的实例,不能直接作用于函数组件,函数组件没有实例,如果想获取函数组件里面的dom 或者是类组件的dom, 还是需要使用 ref 转发来获取
直接作用于类组件
import React, { PureComponent, useCallback, useRef } from 'react' class TestComp extends PureComponent { render() { return ( <> <h1>我是测试组件</h1> </> ) } } export default function TestRefHook() { // ref 对象 const inputRef = useRef<TestComp>(null) // 使用 callback 绑定函数引用,养成习惯 const handle = useCallback((e: React.MouseEvent<HTMLButtonElement>) => { console.log(inputRef.current, '----===='); }, []) return ( <div> <TestComp ref={inputRef} /> <button onClick={handle}>获取类组件的实例</button> </div> ) }
效果
ref hooks 用于固定数据的引用
请使用hooks 来实现一个定时器,我们可能会写以下代码实现。
效果
setTimeout 实现
import React, { useEffect, useState } from 'react' export default function TestRefHook() { // 计时器的数据 const [n, setN] = useState(10) // 使用副作用 useEffect(() => { if (n === 0) return; // 这里为啥要使用setTimeout,因为effect hooks 在初始化的时候会调用函数, // 启动一个定时器,并且在先清理上一次的副作用 const timer = setTimeout(() => { setN(n - 1) }, 1000) return () => { clearTimeout(timer) } }, [n]) return ( <div> <span>计时器</span> <span>{n}</span> </div> ) }
使用 setInterval 来实现
需要每一次都清理掉副作用,不然会多个定时器,出现问题
import React, { useEffect, useState } from 'react' export default function TestRefHook() { // 计时器的数据 const [n, setN] = useState(10) // 使用副作用 useEffect(() => { if (n === 0) return; const timer = setInterval(() => { setN(n - 1) }, 1000) return () => { clearInterval(timer) } }, [n]) return ( <div> <span>计时器</span> <span>{n}</span> </div> ) }
使用ref hooks 来实现
import React, { useEffect, useRef, useState } from 'react' export default function TestRefHook() { // 计时器的数据 const [n, setN] = useState(10) // 使用ref来固定数据 const nRef = useRef(n) // 使用副作用 useEffect(() => { const timer = setInterval(() => { nRef.current-- setN(nRef.current) if (nRef.current === 0) { clearInterval(timer) }; }, 1000) }, []) // 这里不能写任何的依赖,不然会没用 return ( <div> <span>计时器</span> <span>{n}</span> </div> ) }