简单总结一下如何使用React的useRef Hook来使用TypeScript的ref。首先,React中的ref主要是用来分配一个HTML元素的。被分配的HTML元素给了我们必须的读写操作,这让我们可以程序化地调用函数。以下面的例子为例,聚焦一个输入元素:
import * as React from 'react';
const App = () => { const ref = React.useRef();
React.useEffect(() => { if (ref.current) { ref.current.focus(); } }, []);
return <input ref={ref} />;};
export default App;
当在TypeScript中使用这个带有useRef钩的函数组件时,你很可能会遇到一个错误。最好的做法是用null来初始化ref。此外,你必须使用一个类型参数,将 ref 转换成 HTMLInputElement 的类型,并将其作为ref 属性使用的元素:
import * as React from 'react';
const App = () => { const ref = React.useRef<HTMLInputElement>(null);
React.useEffect(() => { if (ref.current) { ref.current.focus(); } }, []);
return <input ref={ref} />;};
export default App;
如果你想为HTML元素使用一个不可变的引用,基本上已经是这样了。然而,有时你想用一个ref 作为实例变量来捕获一个值。例如,一个引用可以记录所有的点击互动:
import * as React from 'react';
const App = () => { const [count, setCount] = React.useState<number>(0);
const ref = React.useRef<number>(0);
const handleIncrement = () => { ref.current++; setCount(count + 1); };
const handleDecrement = () => { ref.current++; setCount(count - 1); };
return ( <> <button onClick={handleIncrement}>+</button> <button onClick={handleDecrement}>-</button>
<div>Count: {count}</div> <div>Buttons {ref.current} times clicked</div> </> );};
export default App;
+-
计数。0
按钮被点击0次
类似的例子,但有一个复杂的对象,我们把类型参数提取为接口:
import * as React from 'react';
interface CounterTracker { increment: number; decrement: number;}
const App = () => { const [count, setCount] = React.useState<number>(0);
const ref = React.useRef<CounterTracker>({ increment: 0, decrement: 0, });
const handleIncrement = () => { ref.current.increment++; setCount(count + 1); };
const handleDecrement = () => { ref.current.decrement++; setCount(count - 1); };
return ( <> <button onClick={handleIncrement}>+</button> <button onClick={handleDecrement}>-</button> <div>Count: {count}</div>
<div> Buttons {ref.current.increment + ref.current.decrement}{' '} times clicked </div>
<div>Increment clicked: {ref.current.increment}</div> <div>Decrement clicked: {ref.current.decrement}</div> </> );};
export default App;
+-
计数。0
按钮0次被点击
递增点击:0
递减点击次数:0
如果你碰巧在React的useRef Hook中以一个没有初始化的实例变量开始,但在代码的后面,那么你将不得不以null初始化React的useRef Hook,并使用基于实际类型的联合类型和null作为类型参数。
import * as React from 'react';
const App = () => { const [seconds, setSeconds] = React.useState<number>(0); const [toggle, setToggle] = React.useState<boolean>(false);
const ref = React.useRef<NodeJS.Timeout | null>(null);
const toggleStopwatch = () => { setToggle(!toggle); };
const resetStopwatch = () => { setToggle(false); setSeconds(0); };
React.useEffect(() => { ref.current = setInterval(() => { if (toggle) setSeconds((state) => state + 1); }, 1000);
return () => { if (ref.current) clearInterval(ref.current); }; }, [toggle]);
return ( <> <div>{seconds}</div>
<button onClick={toggleStopwatch}> {toggle ? 'Stop' : 'Start'} </button>
<button onClick={resetStopwatch}>Reset</button> </> );};
export default App;
0
StartReset
基本上这就是你需要知道的关于使用TypeScript、React的useRef Hook和React的ref的一切。毕竟,通过利用元素上的ref属性,ref被用作HTML元素,或者作为实例变量来跟踪一个不会导致React重新渲染的状态。如果你碰巧发现用TypeScript使用React ref的其他变化,请告诉我,我会把它们添加到本指南中。