iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
Modern Web

前端日常,每天 React 一下系列 第 25

【Day 24】Hook 06:useRef

useRef

useRef 使用方式

const refContainer = useRef(initialValue);

useRef 會回傳一個
擁有 current 屬性的 ref object,
current 屬性的值由 initialValue 初始化得來,
回傳的 ref object 在 component 的生命
週期內都將保持不變。

useRef() 建立的是一個普通的 JavaScript object,
這表示它是可修改(mutable)的,
因此更新 current 的值不會觸發 re-render,
但同樣的,當 useRef 的內容發生變化時,
也不會收到任何通知。

使用 useRef() 和自建一個
JavaScript object 的唯一不同是,
useRef 在每次 render 時
都會返回同一個 ref object。

範例:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

使用 useRef 綁定後,
inputEl 的 current 指向 <input type="text" />

更新 useRef 是 side Effect 的行為,因此必須要在 useEffect 或 event handler 裡執行。


使用情境

  • 計算 Render 次數
  • 用 Imperatively 方法改變 DOM 跟 Child Component
  • 抓取 Previous 的值

計算 Render 次數

由於 state 會在更新後觸發 re-render,
因此可以使用 useRef 來記錄 render 次數

const App = () => {
  const renderCount = useRef(0);  // { current: 0 }
  
  useEffect(() => {
    renderCount.current += 1;
  })
return <p>renderCount.current</p>
}

用 Imperatively 方法操縱 DOM

const App = () => {
  const inputRef = useRef();
  
  const clickHandler = () => {
    inputRef.current.focus()
  }
return 
  <>
    <input type='text' ref={inputRef} />
    <button onClick={clickHandler}>Focus</button>
  </>
}

抓取 Previous 的值

function App() {
  const [name, setName] = useState('');
  const previousName = useRef('');

  useEffect(() => {
    previousName.current = name;
  }, [name])

  return (
    <>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <p> My name is {name} </p>
      <p> My previous name is {previousName.current} </p>
    </>
  )
}

每次 render 後都是嶄新的元件,
所以無法取得上次的 state 值。

這時可以利用 useRef 在 render 完後,
存下本次 state 的值,
這樣在下次 render 時,
useRef 就會顯示前次儲存下來的 state 了。


參考資料


上一篇
【Day 23】與 DOM 的互動:Ref
下一篇
【Day 25】React 與 Immutible
系列文
前端日常,每天 React 一下30

尚未有邦友留言

立即登入留言