ref 基本使用
當你希望 react 記住一個值,但又不想像 useState 會刷新元件時,可以存在 ref 裡。
1 2 3 4 5 6 7
| const ref = useRef(0);
{ current: 0 }
|
綁定 dom 範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const { useEffect, useRef } = React;
let myModal; const App = () => { const inputRef = useRef(null); useEffect(() => { console.log(inputRef); }); return ( <> <button type="button" className="btn btn-primary" ref={inputRef}> 打開 Modal </button> </> ); };
|
- 將 useRef 從 react 解構出來
- 用 useRef 宣告變數,可以先帶入 null
- 在 dom 上加入 ref,綁定宣告好的變數
- 在
useEffect()
,就可取得 ref 的 dom 元素
綁定 bootstrap modal 範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const App = () => { const myModal = useRef(null); const modalRef = useRef(null); const openModal = () => { myModal.current.show(); }; useEffect(() => { myModal.current = new bootstrap.Modal(modalRef.current); });
return ( <> <div className="modal fade" tabIndex="-1" ref={modalRef}></div> </> ); };
|
useRef 不會刷新元件
和 useState 不同,使用 useRef 定義值時,不會重新刷新元件。
1 2 3 4 5 6 7 8 9 10 11
| const [num, setNum] = useState(1); const num2 = useRef(1);
useEffect(() => { setInterval(() => { setNum((pre) => pre + 1); num2.current = num2.current + 1; }, 1000); }, []);
|
Ref 錯誤用法
要避免使用 Ref 取得 dom 元素後,直接賦予值到 Ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const App = () => { const [name, setName] = useState(""); const inputRef = useRef(null);
function focus() { inputRef.current.focus(); inputRef.current.value = "Some value"; }
return ( <> <input ref={inputRef} value={name} onChange={(e) => setName(e.target.value)} /> <div>My Name is {name}</div> <button onClick={focus}>Focus</button> </> ); };
|
如上 inputRef 的 value 被手動賦值,但 input 綁定的 name 並沒有改變。React 通常使用狀態(state)來管理表單輸入,這樣可以確保 UI 與數據的一致性。當你直接修改 input 的 value 時,這不會觸發 React 的狀態更新,因此 UI 和狀態之間可能會不同步。
應該使用 React 的 setName 函數來更新 name 狀態,而不是直接修改 DOM 值:
1 2 3 4
| function focus() { inputRef.current.focus(); setName("Some value"); }
|
動態綁定 ref
假設我們有一個待辦事項列表,每一項需要一個 ref,例如可以讓我們聚焦或操作該項元素。通常情況下,我們不能事先知道有多少項目,因此無法直接使用 useRef 為每個項目分配一個獨立的 ref。這時可以用 ref callback 來動態地為每個列表項分配 ref。
具體實現
以下是實現步驟:
建立一個 refs 物件:使用 refs 物件來儲存每個項目的 ref。
使用 ref 回調:透過回調函數為每個項目設定 ref,並將該 ref 存儲在 refs 物件中。這樣可以確保每個項目的 ref 都被記錄在 refs 中,並可根據需求進行操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { useRef } from 'react';
function TodoList({ items }) { const refs = useRef({});
function setRef(index) { return (element) => { refs.current[index] = element; }; }
return ( <ul> {items.map((item, index) => ( <li key={item.id} ref={setRef(index)}> {item.text} </li> ))} </ul> ); }
|
代碼解釋
- refs 是一個使用 useRef 創建的物件,用於存儲所有項目的 ref。
- setRef 函數是回調函數,會返回一個函數並將元素節點(element)存入 refs 中對應的索引位。這個回調函數在渲染時會依據 index 自動更新每個項目的 ref。
當需要存取某個特定的項目時,直接透過 refs.current[index] 可以取得該項目的 DOM 節點並進行操作。