iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
自我挑戰組

我與 React 的 30天系列 第 16

Day 16 useRef 還有什麼作用

  • 分享至 

  • xImage
  •  

昨天提到了 useRef 的一些簡易的使用方式,今天再來更深入一點,來說說 useref 是為了解決什麼問題吧!

使用 useRef 來計算畫面渲染的次數吧

import { useState } from "react"

const RenderTime = () => {
  const [renderCount, setRenderCount] = useState(0)
  
  useEffect(() => {
    setRenderCount(pervCount => pervCount + 1)
  })
    
  return (

    <div>
      <h1>渲染次數: {renderCount} </h1>
    </div>
  )
}

export { RenderTime }

若是我們使用 useState 去計算畫面渲染的次數的話...

我想聰明的你應該也看出來了,這樣會造成無窮迴圈,因為每次渲染畫面時都會執行 useEffect,進入到 useEffect 又會執行 setRenderCount,這樣又會呼叫 React 再次渲染畫面,就會造成無窮迴圈,這時我們就可以使用 useRef 去紀錄。

因為昨天也提到了使用 useRef 不會渲染畫面,所以我們可以這樣寫

import { useEffect, useState, useRef } from "react"

const RenderTime = () => {
  const [renderCount, setRenderCount] = useState(0)
  const countRef = useRef(0)
  useEffect(() => {
    countRef.current += 1 
  })
  return (

    <div>
      <button onClick={() => setRenderCount(prevCount => prevCount + 1 )}>按我</button>
      <h1>渲染次數: {countRef.current} </h1>
    </div>
  )
}

export { RenderTime }

這樣會畫面只會因為 setRenderCount 而渲染畫面,所以 useEffect 中就只會乖乖的紀錄 countRef.current 的值

useRef 不再讓你用事件綁定 DOM

昨天我們也提到了,在 React 中我們可能會用on.. 系列的事件去綁定元素,但是 useRef 讓我們可以不用讓我們一定要用事件去綁定事件,這樣的效果就很像 原生 JavaScript 的 queryselector 一樣

import { useState, useRef } from "react";
import "./index.css"

const Text = () => {
  const [text, setText] = useState("");
  const textRef = useRef("")

  const textHandler = () => {
    setText(textRef.current.value)
  }

  const inputFocus = () => {
    textRef.current.focus()
  }
  
  return (
    <>
      <div>
        <input type="text" ref={textRef} />
        <div>
          目前文字: {text}
        </div>
        <button className="button" onClick={inputFocus}>按此可以進行輸入</button>
      </div>
      <div className="button">
        <button onClick={textHandler}>送出文字</button>
      </div>
    </>

  )
}

export { Text }

以上面的這個例子,就像是一個表單再填入的時候,我們並不用使用 onChange 事件去監聽,去獲取他每次改變的值,我們只是要獲的 input 最終的值而已,這種情況就很適合使用 useRef

useRef 獲取過去的值?

這兩天我們對於 useRef 的了解就是,他是個物件,其中會有一個 current的屬性,改變 current 不會造成 re-render,我們都知道了這幾點之後,那就讓我們來看看何謂使用 useRef 去獲取過去的值吧~

import { useState, useRef, useEffect } from "react";

const Past = () => {
  const [value, setValue] = useState("")
  const pastRef = useRef("")

  useEffect(() => {
    pastRef.current = value
  }, [value])

  return (
    <>
      <div>
        <input type="text" ref={pastRef} onChange={(e) => setValue(e.target.value)} />
      </div>
      <div>
        現在的輸入框文字:{ value }
      </div>
      <div>
        紀錄過去吧:{ pastRef.current }
      </div>
    </>
  )
}

export { Past }

有沒有覺得很神奇,為什麼 useRef 可以造成這樣的效果呢?
讓我們看看input 標籤,我們綁定一個 onChange 事件,每次輸入框改變的時候就 setvalue,這是就會呼叫 React 重新渲染畫面,而重新渲染畫面其實就是重新執行 Past 這個 function,所以也執行了 useEffect,但是但是但是,這時的 value,並沒有改變他還是上一次的值,只有畫面改變而已

我們可以下面這個例子去驗證這件事

import { useState } from "react";

const Try = () => {
  const [count, setCount] = useState(0)
  
  const checkCount = () =>{
    setCount(pervCount => pervCount + 1 )
    console.log(count);
  }

  return (
    <div>
      <button onClick={checkCount}>點我</button>
      <h1>{count}</h1>
    </div>
  )
}

export { Try }


每次點擊的時候將 count + 1 ,並同時 console.log(count),你會發現畫面變了,可是印出來的值還是點擊前的 count,因為在點擊時做了兩件事,setCount 以及,印出點擊時的 count 所以才會呈現這樣的效果,

所以我們可以用這樣的效果讓 useRef 做到紀錄過去這種事,
這是因為 React 執行渲染的機制,也是 useState 這個 function 造成的

這個例子在我看來就很像 useRef 在用上帝視角看著這個 function,你可以這樣想像,應該會比較容易理解吧!

小結

今天更進一步介紹了 useRef 還可以怎樣作用,雖然可能不知道會不會實際運用到,但是這幾點都可以讓你跟 useRef 變熟,謝謝大家收看~


上一篇
Day 15 useRef 就是不讓你 re-render
下一篇
Day 17 為什麼要渲染我啊,那你有聽過 React.memo 嗎?
系列文
我與 React 的 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言