useRef & the DOM
ref คือกล่องที่อยู่ข้าม render
หัวข้อที่มีชื่อว่า “ref คือกล่องที่อยู่ข้าม render”useRef ให้ container ที่ mutable — object { current: value } — ที่ React เก็บไว้ข้าม render แต่ ไม่เฝ้าดู การเปลี่ยน ref.current ไม่ trigger re-render
const ref = useRef(0);ref.current += 1; // mutate freely — NO re-render happensนั่นคือความต่างทั้งหมดจาก state:
useState | useRef | |
|---|---|---|
| อยู่ข้าม re-render | ✅ | ✅ |
| เปลี่ยนแล้ว re-render | ✅ ใช่ | ❌ ไม่ |
| อ่านตอน render | ✅ (เป็น snapshot) | ⚠️ เลี่ยง (mutable, ไม่ reactive) |
| ใช้สำหรับ | data ที่แสดงใน UI | value ที่ต้องจำแต่ไม่ render |
ใช้ ref สำหรับสิ่งที่ UI ไม่ได้แสดงตรง ๆ: timer id, ค่าก่อนหน้าของบางอย่าง, counter ที่ mutable, scroll position หรือ reference ไปยัง DOM node
// Classic use: hold a timer id so you can clear it later.const intervalRef = useRef(null);function start() { intervalRef.current = setInterval(tick, 1000);}function stop() { clearInterval(intervalRef.current);}ref สำหรับเข้าถึง DOM
หัวข้อที่มีชื่อว่า “ref สำหรับเข้าถึง DOM”การใช้บ่อยที่สุดคือคว้า DOM node — เพื่อ focus input, วัดขนาด element หรือเรียก imperative browser API ผูก ref กับ host element ผ่าน attribute ref หลัง commit ref.current จะชี้ไปยัง DOM node จริง
function SearchBox() { const inputRef = useRef(null); return ( <> <input ref={inputRef} /> <button onClick={() => inputRef.current.focus()}>Focus</button> </> );}นี่คือ escape hatch — คุณกำลังก้าวออกนอก declarative model เพื่อคุยกับ DOM โดยตรง ใช้กับ focus, scroll, การวัดขนาด และการ integrate widget ที่ไม่ใช่ React อย่าใช้ทำสิ่งที่ state ทำได้
React 19: ref เป็นแค่ prop
หัวข้อที่มีชื่อว่า “React 19: ref เป็นแค่ prop”เมื่อก่อน การส่ง ref ผ่าน component ของคุณเองไปยัง DOM node ข้างในต้องห่อ component ด้วย forwardRef ใน React 19 ref เป็น prop ธรรมดา — คุณรับ ref แล้วส่งต่อได้เหมือน prop อื่น ๆ และ ไม่ต้องใช้ forwardRef สำหรับ code ใหม่แล้ว
// ✅ React 19: accept ref as a normal prop — no forwardRef.function MyInput({ placeholder, ref }) { return <input placeholder={placeholder} ref={ref} />;}
// Parent:const ref = useRef(null);<MyInput ref={ref} placeholder="Search" />;form เก่ายังใช้ได้ — forwardRef ไม่ได้ถูกถอดออก — แต่ตอนนี้เป็น legacy component ใหม่ควรรับ ref เป็น prop
สำหรับกรณีที่พบน้อยกว่า ที่คุณอยากเปิดเผย imperative API แบบ custom (ไม่ใช่ raw DOM node) ให้ parent useImperativeHandle ให้คุณกำหนดได้ว่า ref เปิดเผยอะไรบ้าง
function FancyInput({ ref }) { const inputRef = useRef(null); useImperativeHandle(ref, () => ({ focus: () => inputRef.current.focus(), clear: () => { inputRef.current.value = ''; }, })); return <input ref={inputRef} />;}