iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0

接下來會來介紹一下各種其他 React 常用功能。今天我們來說一下要怎麼在 React 中操作元素。一般來說,操作元素會使用 querySelector取得 DOM 元素,做後續操作,但這個做法在 React 中不太直覺,與不直接操作原始 DOM 的 React 不太相同。因此,今天介紹 useRef 來解決這個問題。

useRef 是什麼

useRef 是 React 提供的一個 hook api,可以創造一個 變數 object 綁定在要取用的元素上,讓開發者能夠透過這個 object 取用到這個元素。
useRef 的物件 不會因為元件的 re-render 而改變 object 的 reference,即使元件有所更新, useRef 的物件也不會因此而重新定義,指向其他的 reference。
由於 ref object 不會重新定義的特性,他時常被用在:

  1. 操作 DOM 元素
  2. 計算 counter
  3. 抓取前一次 render 的值
  4. 控制第一次不渲染

接下來分別說明一下。

1. 操作 DOM 元素

使用 useRef 回傳的值是一個包含 current 屬性的 object,我們可以先創建一個 ref object,並將其綁定到元素上:

const Input = ()=>{
    const inputRef = useRef(); // ()中可放入 default value
    
    return (
        <div>
            <input type="text" ref={inputRef}/>
            <button>提交</button>
        </div>
    )
}

接著可以就可以很簡單的操作綁定上的元素,例如,我要在按鈕按下的同時 console.log 出 value:

const Input = ()=>{
    const inputRef = useRef();
    const handleClick = () =>{
        console.log(inputRef.current.value)
    }
    return (
        <div>
            <input type="text" ref={inputRef}/>
            <button onClick={handleClick}>提交</button>
        </div>
    )
}

2. 計算 counter

由於 useRef 有不會隨著 re-render 更新的特性,因此很適合作為計算次數的方法。
例如,需要計算 render 次數的話,可以這樣寫:

const Counter =()=>{
    const [name, setName] = useState("");
    const counter = useRef(0);
    
    useEffect(()=>{
        counter.current += 1;
    }, [name])
    return (
        <div>
            <input type="text" value={name} onChange={()=> setName(e.target.value)}/>
            <p>重新渲染次數:{counter.current}</p>
        </div>
    )
}

這樣每當輸入 value,由於 state 被更新,整個元件會重新 render,並會觸發 useEffect ,counter 值也因此更新。

3. 抓取前一次 render 的值

由於 ref object 不會跟著更新的特性,也可以拿來記錄前一次 render 的 state 值,避免因為 re-render 造成前一次的值消失。

const Previous = ()=>{
    const [name, setName] = useState("");
    const previousName = useRef("");
    
    useEffect(()=>{
        previousName.current = name;
    }, [name])
    
    return (
        <div>
            <input type="text" onChange={(e)=> setName(e.target.value)}/>
            <p>前一個名字:{previousName.current}</p>
        </div>
    )
}

這裡順序是這樣的:
第一次渲染 > useEffect (previousName 記憶本次的 name) > state 改變 > 第二次渲染 (渲染出previousName) > useEffect (更改 previousName) > 第三次渲染 ...
原理便是使用 ref object 紀錄本次的 state,並在下一次的渲染中呈現出來。

4. 控制第一次不渲染

這邊的控制第一次不渲染的意思是,第一次時不希望出現某個東西,之後渲染再出現。可以搭配 useEffect 使用。引用這篇的寫法:

  const mounted=useRef(false);
    useEffect(()=>{
      if(mounted.current===false){
        mounted.current=true;
        /* 下面是 第一次渲染後 */
    
    
        /* 上面是 第一次渲染後 */      
      }
      else{
        /* 下面是元件更新後 */
    
    
        /* 上面是元件更新後 */

      }
      
      // 移除元件時清除 useEffect
      return (()=>{
           /* 下面是元件移除前 */
      
      
          /* 上面是元件移除前 */
      })
    },[dependencies參數]);

在第一次渲染中做/不做某個動作,並設定 ref object 為 true,之後 render 就可以執行其他動作。換句話說,也就是用不會變動 reference 的物件作條件控制。


以上就是 useRef 的介紹,光是操控 DOM 就相當實用,其他用法也是對寫 React 大有助益,可以試著在自己的 app 中寫看看~

參考資料
【Day.15】React入門 - 非控制組件與useRef
[React Hook 筆記] useRef


上一篇
[Day22]用 React 讓網站動起來:更多 React Hook Form
下一篇
[Day24]用 React 讓網站動起來:useRecucer
系列文
用React讓網頁動起來: React基礎與實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言