useRef 介绍
官方解释:useRef 是一个 React 钩子,可让你引用渲染不需要的值。
个人理解:useRef 允许你在组件的整个生命周期内保持一个不需要渲染的值的引用,useRef 返回的是一个可变的 ref 对象。
语法
-
initialValue:初始化参数。
-
ref:可以通过给元素设置 ref 属性,并传入 useRef() 返回的 ref 对象。
useRef 是 React 中的一个 Hook,它允许你在函数组件中“记住”任何可变值,类似于在类组件中使用的实例变量。useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递给 useRef() 的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
const ref = useRef(initialValue)
用法
1. useRef 存储的变量和常规变量的区别?
const VariateComparison = () => {
let [num, setNum] = useState(1)
let ref = useRef(null)
let variate = null
const handleChange = () => {
setNum(a => a + 1)
}
useEffect(() => {
ref.current = num
// 对于variate的赋值会在每次渲染前丢失
// variate = num
}, [num])
if (num !== 1) {
console.log('ref.current', ref.current) // 获取的是每次num更新前的值
console.log('variate', variate) // 获取的始终是全局状态null
}
return (
<div className="box">
<p>1.useRef存储的变量和常规变量的区别</p>
<button onClick={handleChange}>更新数字:{num}</button>
</div>
)
}
代码演示
useRef 允许你在每次渲染之间存储信息,而常规的变量会在渲染时被重置。所以当点击更新数字的时候,虽然在 num 每次更新的时候都会把 num 的值分别赋值给 ref.current 和变量 variate,但是在重新渲染的时候 ref.current 的值被保存而 variate 的值被重置。
2. 更新 useRef 不会触发重新渲染。
const UpdateRef = () => {
const num = useRef(1)
const handleChange = () => {
num.current = 2
}
return (
<div className="box">
<p>2.更改useRef不会触发重新渲染</p>
<button onClick={handleChange}>更新数字:{num.current}</button>
</div>
)
}
代码演示
与 useState 不同,更新 useState 会触发重新渲染,而更新 useRef 不会触发重新渲染。
3. 操作 DOM,聚焦文本输入。
使用引用操作 DOM 是一种常见的做法,首先使用 useRef 创建一个引用对象,然后将引用对象作为 ref 传递给你需要操作的 DOM,然后通过引用对象的 current 属性拿到该 DOM 的节点。
const FocusingInput = () => {
const inputRef = useRef(null)
const handleClick = () => {
inputRef.current.focus()
}
return (
<div className="box">
<p>3.使用useRef操作DOM,聚焦文本输入</p>
<input ref={inputRef} />
<button onClick={handleClick}>Focus the input</button>
</div>
)
}
代码演示
上面的案例就是通过获取 input 的 DOM 使文本聚焦。
故障排查
1.无法获取自定义组件的引用?
当我们尝试获取自定义租价的 ref 时,这时控制台会提示函数组件不能给出 refs,但是可以用 React.forwardRef()。
const CustomComponent = () => {
const inputRef = useRef(null)
const handleClick = () => {
console.log(inputRef.current)
}
const MyInput = () => {
return <input />
}
return (
<div className="box">
<p>1.无法获取自定义组件的引用</p>
<MyInput ref={inputRef} />
<button onClick={handleClick}>获取DOM</button>
</div>
)
}
使用 forwardRef 去包裹一下 ref,并将 ref 传递给自组件的 ref,这个时候就可以获取到子组件的 ref 了。
const CustomComponent = () => {
const inputRef = useRef(null)
const handleClick = () => {
console.log(inputRef.current)
}
const MyInput = forwardRef((props, ref) => {
return <input ref={ref} />
})
return (
<div className="box">
<p>1.使用forwardRef获取自定义组件的引用</p>
<MyInput ref={inputRef} />
<button onClick={handleClick}>获取DOM</button>
</div>
)
}
代码演示
注意事项
-
useRef 不会在组件之间共享数据。如果你需要在组件之间共享数据,请考虑使用 React Context 或 Redux 等状态管理库。
-
useRef 返回的 ref 对象在组件的整个生命周期内保持不变,这意味着你可以安全地在多个渲染之间访问 .current 属性,而无需担心它会被重新创建。
-
更改 .current 属性的值不会引起组件的重新渲染。如果你需要基于某些值的更改来重新渲染组件,请考虑使用 useState 或 useReducer。