บันทึกการใช้งาน useRef createRef และ forwardRef ของ React
· 4 min read
Table of contents
Intro
สวัสดีครับ บทความนี้จะเป็นการบบันทึกการใช้งาน useRef createRef และ forwardRef ของ React โดย useRef และ createRef ม ีความคล้ายคลึงกันมากและแตกต่างกันอย่างไรมาดูกัน 🚀
TL; DR;
- useRef คือ React Hooks ที่สามารถเข้าถึงโดยการ Reference ไปที่ DOM element ใช้กับ Functional component สามารถทำ initialValue (.current) ได้
- createRef คือ วิธีการ Access DOM nodes ด้วยการ Reference ใช้กับ Class component (การทำงานคล้ายกับ useRef)
- forwardRef คือ การส่งต่อ Ref จาก Parent ไปที่ Child เมื่อสร้างเป็น Ref เป็น Component
ตัวอย่างการใช้งาน useRef
Live Editor
() => { const inputRef = useRef("") const [value, setValue] = useState("") return ( <> ดึงค่าจาก Element: {value} <hr /> <input ref={inputRef} type="text" placeholder="Enter text ..." /> <button onClick={() => { setValue(inputRef.current.value) }}>Value</button> </> ) }
Result
Loading...
Live Editor
() => { const divRef = useRef("") const [value, setValue] = useState("") return ( <> ดึงค่าจาก Element: {value} <hr /> <div ref={divRef} data="some value">Some content</div> <button onClick={() => { const el = divRef.current // <div text="some value">Some value</div> console.log(el) // some vale console.log(el.attributes.data.value) // Some content console.log(el.innerText) el.innerText = "Hello World!" setValue(el.innerText) }}>Value</button> </> ) }
Result
Loading...
ความเหมือนกันระหว่าง useRef และ createRef
ถ้าดูแค่ผิวเผินอาจจะดูความแตกต่างของผลลัพธ์ไม่ออกเลย เพราะทั้งสอง Component นั้นให้ผลลัพธ์เหมือนกัน
Live Editor
() => { const TextInputWithSelectTextButton1 = () => { const inputEl = useRef(null) const onButtonClick = () => { inputEl.current.select() }; return ( <> <input ref={inputEl} type="text" placeholder="Enter text ..." /> <button onClick={onButtonClick}>Select Text</button> </> ); } const TextInputWithSelectTextButton2 = () => { const inputRef = createRef() const onButtonClick = () => { inputRef.current.select() }; return ( <> <input ref={inputRef} type="text" placeholder="Enter text ..." /> <button onClick={onButtonClick}>Select Text</button> </> ); } return ( <> <TextInputWithSelectTextButton1 /> <hr /> <TextInputWithSelectTextButton2 /> </> ) }
Result
Loading...
ความแตกต่างระหว่าง useRef และ createRef
Live Editor
() => { const [renderIndex, setRenderIndex] = useState(1) const refFromUseRef = useRef(null) const refFromCreateRef = createRef() if (!refFromUseRef.current) { refFromUseRef.current = renderIndex; } if (!refFromCreateRef.current) { refFromCreateRef.current = renderIndex; } return ( <> Current render index: {renderIndex} <br /> First render index remembered within refFromUseRef.current: {refFromUseRef.current} <br /> refFromCreateRef.current = Current render index: {refFromCreateRef.current} <br /> <button onClick={() => setRenderIndex((prevState) => prevState + 1)}> Cause re-render </button> </> ) }
Result
Loading...
Live Editor
() => { const valueRef = React.useRef(100) return ( <> เมื่อต้องการเปลี่ยนแปลงค่า Ref ให้อัปเดตค่า current<br /> แต่ตัวอย่างนี้ค่า current จะไม่เปลี่ยนแปลง<br /> ต้องใช้วิธีบางอย่างให้ทริกเกอร์ Re-Render Compoent ตามตัวอย่างถัดไป<hr /> Value: {valueRef.current}<br /> <button onClick={() => { valueRef.current = 150 }}>Increase</button> </> ) }
Result
Loading...
Live Editor
() => { const valueRef = React.useRef(100) const [, setState] = useState(0) return ( <> ใช้ Hooks useState เพื่ออัปเดต อะไรบางอย่างเข้ามาช่วยเพื่อ Re-Render<br /> ก็จะสามารถทำให้ค่าใน current เปลี่ยน<hr /> Value: {valueRef.current}<br /> <button onClick={() => { valueRef.current = 150 setState(1) }}>Increase</button> </> ) }
Result
Loading...
Live Editor
() => { const valueRef = React.createRef() const [, setState] = useState(0) return ( <> แม้ว่า createRef ควรใช้กับ Class component<br /> แต่ก็ใช้กับ Functional component ได้เช่นกัน<br /> แต่เมื่อ Component มีการอัปเดต App ก็จะถูก Re-Render ใหม่<br /> createRef ก็จะเริ่มต้น Reference ใหม่ทั้งหมด<br /> ดังนั้นทำให้การอัปเดตค่า current ไม่มีผล<br /> เป็นเหตุผลที่ควรใช้ Hooks useRef แทน<hr /> Value: {valueRef.current}<br /> <button onClick={() => { valueRef.current = 150 setState(1) }}>Increase</button> </> ) }
Result
Loading...
การใช้งาน forwardRef
forwardRef คือ การส่งต่อ Ref จาก Parent ไปที่ Child เมื่อสร้างเป็น Ref เป็น Component (Custom)
Live Editor
() => { const ref = React.useRef(null); const alertText = () => { const input = ref.current if (input.value) alert(input.value) else input.focus() } const InputText = React.forwardRef((props, ref) => ( <input ref={ref} {...props} /> )) return ( <> <InputText ref={ref} placeholder="Enter text..." /> <button onClick={alertText}>Focus</button> </> ) }
Result
Loading...
สรุป
ใช้ useRef
- ใช้กับ Functional component
- สามารถกำหนด initialValue (.current) ได้
- เพื่อรักษาค่า Ref ปัจจุบันใช้อยู่ตลอดการใช้งานของ Functional component และเมื่อมีการ Re-Render จะไม่สร้างค่า Ref ขึ้นมาใหม่
- ความสามารถในการทำ Memorize
- อัปเดตค่า .current ได้ (แต่ต้องสั่ง Trigger อะไรบางอย่างให้ Re-Render จากนั้นค่าที่กำหนดถึงจะเปลี่ยนแปลง)
ใช้ createRef
- ใช้กับ Class component
- เมื่อต้องการรีเช็ต Ref ใหม่ทุกครั้งที่มีการ Re-Render
ใช้ forwardRef เมื่อต้องการส่งต่อ Ref จาก Parent ไปที่ Child เมื่อสร้างเป็น Ref เป็น Component