【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 26 什麽样的测试应该写,什麽样的不用?

>>:  连续 30 天 玩玩看 ProtoPie - Day 25

不只懂 Vue 语法:後记 - 为自己坚持 30 天的参赛心得

终於完赛了,这篇文章会以个人完赛心得为主,可谓是零技术成分。(撒花~ 我以为完赛都是这样: 最後才没...

Day 13 | 同步与非同步- Thread类别与runOnUiThread()方法

Thread Thread是Java的原生类别,当需要执行绪处理费时任务时,就可以新增该类别执行Ta...

用Stack 制作Queue

记录学习内容。 以下内容和截图大多引用文章。 还不了解,内容可能有错误。 Queue 可以用 Sta...

Day 14 储存宝石:S3是什麽? S3 vs EBS 方案比较

今天我们将来了解 S3 与 EBS 这两种储存方案的各自特点,并为大家介绍 AWS S3 在整体架...

Day03 - 【入门篇】浅谈身份验证与授权(1)

本系列文之後也会置於个人网站 在「快速开始」的单元中,实际上已经完成了所有身份识别、身份验证、授权...