接下來會來介紹一下各種其他 React 常用功能。今天我們來說一下要怎麼在 React 中操作元素。一般來說,操作元素會使用 querySelector
取得 DOM 元素,做後續操作,但這個做法在 React 中不太直覺,與不直接操作原始 DOM 的 React 不太相同。因此,今天介紹 useRef 來解決這個問題。
useRef
是 React 提供的一個 hook api,可以創造一個 變數 object 綁定在要取用的元素上,讓開發者能夠透過這個 object 取用到這個元素。useRef
的物件 不會因為元件的 re-render 而改變 object 的 reference,即使元件有所更新, useRef 的物件也不會因此而重新定義,指向其他的 reference。
由於 ref object 不會重新定義的特性,他時常被用在:
接下來分別說明一下。
使用 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>
)
}
由於 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
值也因此更新。
由於 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,並在下一次的渲染中呈現出來。
這邊的控制第一次不渲染的意思是,第一次時不希望出現某個東西,之後渲染再出現。可以搭配 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