Table of contents
Intro
สวัสดีครับ บทความนี้จะแนะนำแนวทางการใช้งาน React Hooks ที่ชื่อ useMemo และ useCallback คืออะไร มีความสำคัญอย่างไร ช่วยเพิ่มประสิทธิภาพลดการ Render ของ React ที่หนักหน่วงอย่างไร ควร Refactor อย่างไร มาดูกันเลยครับ 😍
TL; DR;
- useMemo คือการ Cache ค่า Value ถูกเรียกครั้งแรกเมื่อมีการ Render และครั้งต่อไปเมื่อมีการ Re-Render
และ
ค่าใน Array deps มีการเปลี่ยนแปลง โดย Return ออกเป็นค่า Value - useCallback คือการ Cache Function
ไม่
ถูกเรียกครั้งแรกเมื่อมีการ Render โดยจะถูกเรียกก็ต่อเมื่อสั่ง Call ฟังก์ชันและ
ค่าใน Array deps มีการเปลี่ยนแปลง โดย Return ออกเป็น Function
เริ่มกันเลย
ปัญหา Re-Render
ปัญหาการ Re-Render นั้นเป็นปัญหาใหญ่ ที่ทำให้เกิดการ Render ที่หนักหน่วง ตามปกติทุกการ Render จะเกิดการจอง Memory (Memory allocation) และบางทีการ Render Component ซ้ำ ๆ เกินความจำเป็นอาจจะทำให้เกิดการจัดสรรหน่วยความจำอย่างไม่ถูกต้อง (Memory Leak) ได้
แก้ปัญหาด้วย useMemo
ในตัวอย่างนี้จะใช้การวิธีการแสดงค่า Timestamp ของฟังก์ชัน Date เป็นกรณียกตัวอย่างเมื่อหน้าเว็บถูก Re-Render ในแต่ละครั้ง
แบบไม่ใช้ useMemo
- Timestamp แสดงครั้งแรกเมื่อมีการ Render
- Timestamp แสดงอีกครั้งเมื่อมีการ Re-Render (Number หรือ Some Value เปลี่ยนแปลง)
- เป็นตัวอย่างกรณีการ Re-Render เกินความจำเป็น
แบบใช้ useMemo
- Timestamp แสดงครั้งแรกเมื่อมีการ Render
- Timestamp แสดงอีกครั้งเมื่อมีการ Re-Render และ ค่า Some Value มีการเปลี่ยนแปลงเท่านั้น
- เป็นตัวอย่างกรณีการ Re-Render เฉพาะที่จำเป็น
แก้ปัญหาด้วย useCallback
ในตัวอย่างนี้จะใช้การวิธีการแสดงค่า Timestamp ของฟังก์ชัน Date เป็นกรณียกตัวอย่างเมื่อหน้าเว็บถูก Re-Render ในแต่ละครั้ง
แบบไม่ใช้ useCallback
- Timestamp แสดงครั้งแรกเมื่อมีการ Render
- Timestamp แสดงอีกครั้งเมื่อมีการ Re-Render (Number หรือ Some Value เปลี่ยนแปลง)
- เป็นตัวอย่างกรณีการ Re-Render เกินความจำเป็น
แบบใช้ useCallback
- Timestamp ไม่แสดงครั้งแรกเรียกเมื่อมีการ Render (จะแสดงเมื่อเราสั่ง Call ฟังก์ชันเอง)
- Timestamp แสดงเมื่อสั่ง Call ฟังก์ชัน และ ค่าใน Some Value มีการเปลี่ยนแปลงเท่านั้น
- เป็นตัวอย่างกรณีการ Re-Render เฉพาะที่จำเป็น
สรุป
หลักการของ useMemo คือการ Cache ข้อมูลไว้
- ถูกเรียกครั้งแรกเมื่อมีการ Render
- ถูกเรียกอีกครั้งเมื่อมีการ Re-Render
และ
ค่าใน Array deps มีการเปลี่ยนแปลง - Return ออกเป็นค่า Value
หลักการของ useCallback คือการ Cache ฟังก์ชันไว้
ไม่
ถูกเรียกเมื่อมีการ Render (จะถูกเรียกเมื่อเราสั่ง Call ฟังก์ชันเอง)- ถูกเรียกอีกครั้งเมื่อสั่ง Call ฟังก์ชัน
และ
ค่าใน Array deps มีการเปลี่ยนแปลง - Return ออกเป็น Function
useCallback(fn, deps) จะเท่ากับ useMemo(() => fn, deps)
ทั้งสองตัวมีการทำงานที่คล้ายกัน และแตกต่างกันนิดหน่อย แต่ทั้งสองสามารถช่วยเพิ่มประสิทธิภาพเพื่อช่วยลดการ Re-Render ในบางกรณีที่เกินความจำเป็นได้ และต้องเลือกใช้ตามความเหมาะสมดังนี้
- เมื่อ Client ใช้ Device สเปคเครื่องไม่ค่อยแรง React อาจจะหน่วงและช้ามาก ๆ ซึ่งการ Optimize render ก็อาจจะช่วยไปได้เยอะมาก ๆ
- useMemo ใช้เมื่อถ้ามีการคำนวณอะไรที่ใช้เวลานานมาก ๆ และต้องการทำ Memorizes ไว้ แต่ในการกลับกัน ไม่ควรใช้กับการคำนวณง่าย ๆ เช่น 1 + 1 เพราะเป็นปกติจะได้ผลลัพธ์เร็วอยู่แล้ว และอาจจะทำให้เกิด Overhead เปล่า ๆ
- เมื่อมี Component ซับซ้อนและเยอะ และมี Logic เยอะ ที่เป็น Parent Child หลายชั้น ถ้าไม่มีการทำ Optimize render อาจจะช้าและค้างได้เลย
- Input Form ที่มีฟิลด์เยอะ ๆ ถ้าไม่คำนึงเรื่องพวกนี้ ถ้าเวลาพิมพ์ เร็ว ๆ จะสะดุดมาก ๆ
รายละเอียดเทคนิคอื่น ๆ
- React ถ้าใช้ useEffect ควรเขียน Cleanup functions วิธีใช้งานแบบผิด ๆ ที่มือใหม่อาจจะพลาด
- เพิ่มประสิทธิภาพลดขนาด App bundle size ด้วย Dynamically Importing กับ React.lazy
- Debouncing คืออะไร ?
- Throttling คืออะไร แตกต่างกับ Debouncing อย่างไร (ตอนจบ)
- บันทึกการใช้งาน useRef createRef และ forwardRef ของ React
- เจาะลึกความลับ Shallow และ Deep Copies ใน JavaScript (ตอนที่ 1)