掌握 React 和 TypeScript 中的 'useRef':'useRef' 的 4 个不同用例
在 React 中,useRef 是一个功能强大的 Hook,它允许开发者与 DOM 交互并管理可变值,而无需触发页面重新渲染。当与 TypeScript 结合使用时,它的功能更加强大,能够提供类型安全并防止常见的运行时错误。本文将探讨 useRef 在 React 中的各种应用场景,重点介绍如何在 TypeScript 项目中高效使用它。
了解 useRef:
React 中的 useRef hook 提供了一个可变对象,称为“ref”。这个 ref 可以保存对 DOM 元素或其他任何值的引用,并且在渲染过程中保持不变。与状态变量不同,更改 ref 的值不会触发组件的重新渲染,这使得它非常适合某些特定场景。
基本用法
以下是如何在函数式组件中使用 useRef 的方法:
import React, { useRef } from 'react';
function MyComponent() {
const myRef = useRef(null);
// Accessing the current value of the ref
console.log(myRef.current);
return <div ref={myRef}>Hello, useRef!</div>;
}
在上面的例子中,我们创建了一个名为 myRef 的引用,并使用 ref 属性将其附加到一个 DOM 元素上。您可以使用 myRef.current 访问该引用的当前值。
React 和 TypeScript 中 useRef 的使用场景
1. 访问 DOM 元素
useRef 最常见的使用场景之一是直接访问 DOM 元素。这对于诸如聚焦输入字段或测量元素尺寸等任务非常有用:
import React, { useRef, useEffect } from 'react';
function AutoFocusInput() {
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return <input ref={inputRef} />;
}
在这个例子中,inputRef 允许我们在组件挂载时聚焦输入元素,而无需状态变量来触发重新渲染。
2. 存储先前值
useRef 可用于存储和比较不同渲染之间的先前值。这对于检测 props 或 state 的变化非常有用:
import React, { useRef, useEffect } from 'react';
function ValueChangeDetector(props: { value: number }) {
const prevValueRef = useRef<number | undefined>();
useEffect(() => {
if (prevValueRef.current !== undefined && prevValueRef.current !== props.value) {
console.log('Value changed:', prevValueRef.current, '->', props.value);
}
prevValueRef.current = props.value;
}, [props.value]);
return <div>{props.value}</div>;
}
在这里,prevValueRef 存储 value prop 的先前值,使我们能够比较它并在它发生变化时采取操作。
3. 存储非托管值
useRef 可用于存储那些更改时不会触发重新渲染的值。这对于缓存耗时的计算或不属于组件状态的值非常有用:
import React, { useRef, useState } from 'react';
function ExpensiveComponent() {
const expensiveValueRef = useRef<number>(0);
const [count, setCount] = useState<number>(0);
const calculateExpensiveValue = () => {
if (expensiveValueRef.current === 0) {
// Perform expensive calculation
expensiveValueRef.current = /* ... */;
}
return expensiveValueRef.current;
};
return (
<div>
<p>Expensive Value: {calculateExpensiveValue()}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
在这个例子中,expensiveValueRef 存储了昂贵计算的结果,确保计算只发生一次。
4. 与第三方库交互
当将 React 与依赖可变值的第三方库或 API 集成时,可以使用 useRef 来维护引用并安全地与这些库交互:
import React, { useRef, useEffect } from 'react';
import { Chart } from 'chart.js';
function ChartComponent(props: { data: number[] }) {
const chartRef = useRef<HTMLCanvasElement | null>(null);
const chartInstance = useRef<Chart | null>(null);
useEffect(() => {
if (chartRef.current) {
chartInstance.current = new Chart(chartRef.current, {
type: 'line',
data: {
labels: [...Array(props.data.length).keys()],
datasets: [
{
label: 'Data',
data: props.data,
borderColor: 'blue',
},
],
},
});
}
return () => {
if (chartInstance.current) {
chartInstance.current.destroy();
}
};
}, [props.data]);
return <canvas ref={chartRef} />;
}
这里,chartRef 保存着对 canvas 元素的引用,chartInstance 保存着对 Chart 实例的引用。我们在 useEffect 钩子函数中安全地创建和销毁图表。
结论:
React 中的 useRef hook 与 TypeScript 结合使用时,是一个强大的工具,它允许你在保持类型安全的同时,高效地处理可变值并与 DOM 交互。理解 useRef 的各种用例和最佳实践将有助于你编写更简洁、更高效的 React 组件。无论你是管理 DOM 元素、跟踪历史值、缓存数据还是与外部库交互,useRef 都是你 React 工具包中不可或缺的宝贵工具。