react useRef的兩層用法,開眼界了

anchovy發表於2022-06-15

相信有過 React 使用經驗的人對 ref 都會熟悉,它可以用來獲取元件例項物件或者是DOM物件。

useRef 這個 hooks 函式,除了傳統的用法之外,它還可以“跨渲染週期”儲存資料。

首先來看一下它傳統的用法:

import React, { useState, useEffect, useMemo, useRef } from 'react';

export default function App(props){
  const [count, setCount] = useState(0);

  const doubleCount = useMemo(() => {
    return 2 * count;
  }, [count]);

  const couterRef = useRef();

  useEffect(() => {
    document.title = `The value is ${count}`;
    console.log(couterRef.current);
  }, [count]);
  
  return (
    <>
      <button ref={couterRef} onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button>
    </>
  );
}

程式碼中用 useRef 建立了 couterRef 物件,並將其賦給了 buttonref 屬性。這樣,通過訪問 couterRef.current 就可以訪問到 button 對應的 DOM 物件。

然後再來看看它儲存資料的用法。

在一個元件中有什麼東西可以跨渲染週期,也就是在元件被多次渲染之後依舊不變的屬性?第一個想到的應該是 state。沒錯,一個元件的 state 可以在多次渲染之後依舊不變。但是,state 的問題在於一旦修改了它就會造成元件的重新渲染。

那麼這個時候就可以使用useRef來跨越渲染週期儲存資料,而且對它修改也不會引起元件渲染。

import React, { useState, useEffect, useMemo, useRef } from 'react';

export default function App(props){
  const [count, setCount] = useState(0);

  const doubleCount = useMemo(() => {
    return 2 * count;
  }, [count]);

  const timerID = useRef();
  
  useEffect(() => {
    timerID.current = setInterval(()=>{
        setCount(count => count + 1);
    }, 1000); 
  }, []);
  
  useEffect(()=>{
      if(count > 10){
          clearInterval(timerID.current);
      }
  });
  
  return (
    <>
      <button ref={couterRef} onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button>
    </>
  );
}

在上面的例子中,我用 ref 物件的 current 屬性來儲存定時器的ID,這樣便可以在多次渲染之後依舊儲存定時器ID,從而能正常清除定時器。

更多前端知識,請關注小程式,不定期有驚喜!
image.png

相關文章