useEffect คืออะไร เกี่ยวข้องกับ React Lifecycle ยังไงกันนะ มาดูกันนน
สวัสดีค่าา ขออนุญาตแนะนำตัวก่อนนะคะ ชื่อ กรีน ค่ะ นี่เป็นบทความแรกในตำแหน่ง Mobile Developer ของบริษัท 20scoopsCNX เป็นน้องใหม่สุด ๆ ได้มีโอกาสมาจับ React Native เป็นครั้งแรกเลยทำสรุปง่าย ๆ ตามความเข้าใจ และเป็นการทบทวนตัวเองด้วย หากมีข้อผิดพลาดประการใดขออภัยด้วยนะคะ 🙏
ทุกคนเคยสงสัยกันมั้ยว่า Lifecycle ใน React Hooks เนี่ยคืออะไร เกี่ยวข้องยังไงกับ React Lifecycle ของ Class Component แบบเดิม กับ Functional Component แบบใหม่ใน Hooks เหมือนหรือต่างกันยังไง วันนี้เราจะมาสรุปให้ฟังภาพรวมง่าย ๆ ย้ำ ตามความเข้าใจของเรานะ
ก่อนอื่นเลย Lifecycle ใน React จะมีเหตุการณ์หลัก ๆ 3 เหตุการณ์ ได้แก่
- Mounting: ส่วนของการสร้าง Component โดยจะถูกเรียกครั้งแรกครั้งเดียว
- Updating: ขั้นตอนเมื่อมีการอัพเดทข้อมูล หรือ Re-Render
- Unmounting: ส่วนสุดท้ายที่จะทำงานก่อนที่ Component จะถูกทำลายไป
Component Lifecycle
อย่างที่ได้กล่าวมาข้างต้นว่า Lifecycle ของ Component มีอะไรมั่ง ทีนี้เราจะมาขยายความว่าแต่ละ Events มีหน้าที่อะไร และมีการทำงานยังไง ไปดูกันนน 😀
1. Mounting
- constructor: ฟังก์ชันที่ถูกเรียกเป็นฟังก์ชันแรกแต่เรามองไม่เห็นต้อง Override ออกมา ส่วนใหญ่จะใช้ฟังก์ชันนี้ในการ Initial State ของ ตัวแปร หรือ Object, Binding Functio, Ref และอื่น ๆ แต่ถ้าหากใน Component เราไม่ต้องการทำส่วนนี้ก็ไม่ต้อง Handle ตรงนี้ก็ได้ เช่น Stateless Component เป็นต้น
- componentWillMount: ฟังก์ชันจะถูกเรียกก่อนการ render ซึ่งหลัง ๆ มาคนไม่ค่อยใช้กันเพราะถ้าจะ Initial ก็ใส่ไว้ใน Constructor หรือ ถ้าจะจัดการ DOM ก็จะทำใน componentDidMount มากกว่า
- componentDidMount: อย่างที่บอกไปในข้อด้านบน ส่วนใหญ่จะใช้ฟังก์ชันนี้แทน componentWillMount แล้วทำอะไรล่ะ ก็เช่น การดึงข้อมูลจาก APIs หรือการ Subscription Events ต่าง ๆ ไปจนถึงการเอาข้อมูลที่ได้มาไป Process ต่อเพื่อนำไปแสดงผล เป็นต้น
2. Updating
- componentWillRecieveProps(nextProps): ฟังก์ชันนี้จะทำงานก่อนการ render() โดยใช้ในการตรวจเช็คกรณีเมื่อ Props ที่เรามีเกิดการเปลี่ยนแปลงหรือเมื่อได้รับค่าใหม่เข้ามา เช่น เช็คเปรียบเทียบระหว่าง
nextProps
กับthis.props
(ค่าปัจจุบัน) ว่าถ้าเกิดค่านี้เปลี่ยนไปนะ ก็ให้ setState() เป็นต้น - componentWillUpdate(nextProps, nextState): ฟังก์ชันนี้จะถูกเรียกก่อนการ render() และตอนที่ Props หรือ State มีการเปลี่ยนแปลง เช่น อยากทำงานอะไรสักอย่างก่อนเกิดการ render() ยกเว้นการ setState() (เพราะอาจทำให้เกิด Infinity Loop ได้)
- componentDidUpdate(prevProps, prevState): จะถูกเรียกหลังเกิดการ render() ไปแล้ว เช่นเดียวกับการอัพเดตอื่นๆ เราสามารถทำการ Execute ฟังก์ชันอื่น ๆ ได้ที่นี่ เช่น การดึงข้อมูลจาก APIs โดยจะเทียบกับค่าใน Props หรือ State ก่อนหน้าว่ามีการเปลี่ยนแปลงหรือไม่ก็ได้
- shouldComponentUpdate(nextProps, nextState): ฟังก์ชันที่ใช้กำหนดเงื่อนไขต่าง ๆ ว่าเราควรจะทำการ Re-Render เมื่อไหร่และตอนไหนเพื่อลดการทำงานที่ไม่จำเป็นลง ซึ่งฟังก์ชันนี้จะ Return ค่าเป็น Boolean ถ้าหากว่าไม่เขียนฟังก์ชันนี้ Component จะกำหนดค่า Default เป็น
true
เสมอ และจะทำการ Re-Render เมื่อ Props หรือ State มีการเปลี่ยนแปลง และ ถ้าหากเงื่อนไขใน shouldComponentUpdate return ค่าเป็นfalse
ทั้ง componentWillUpdate และ componentDidUpdate จะไม่ถูกเรียกใช้งาน
3. Unmounting
- componentWillUnmount: จะเรียกเมื่อเราจะทำการเปลี่ยน Component (เมื่อเปลี่ยน Component เช่น ปิดหน้า A แล้วเรียกหน้า B ซึ่ง Component หน้า A จะถูกทำลายทิ้ง) ฟังก์ชันนี้ส่วนใหญ่จะใช้ในการปิดการทำงานของ Services ต่างๆเพื่อ Clear Memory รวมไปถึงการป้องกันการอัพเดทที่เราไม่ต้องการเป็นการ Make Sure การทำงานของ Garbage Collection ไปในตัวด้วย 🙌
โดยที่ Component Lifecycle จะทำงานร่วมกับ Class Component ส่วน useEffect ที่จะพูดถึงต่อไปนั้น ทำงานร่วมกับ Functional Component
แปะลิ้งค์ Class component กับ Functional Component ไปอ่านทำความเข้าใจกันได้นะคะ (ไปโล้ดดด) 👇
useEffect
useEffect เป็นส่วนหนึ่งใน Lifecycle Hooks ของ React ที่เข้ามาใหม่เพื่อทำให้ชีวิตเราง่ายขึ้น โดย useEffect จะรวมเหตุการณ์ทั้ง componentDidMount, componentDidUpdate และ componentWillUnmount ไว้ใน Function เดียว!
Example Code: ด้านบนคือการทำงานของ Timer โดยหลังจากที่ Render แล้ว useEffect ก็จะถูกเรียกใช้งาน โดยฟังก์ชัน useEffect จะรับตัวแปร 2 ตัวแปร คือ Function และ Array
โดยตัว Function ทำงานตามคำสั่งเหมือนกับ componentDidMount ซึ่งจากตัวอย่าง Code คือการ setInterval
และ clearInterval
ส่วนตัวแปร Array ถ้าไม่ใส่เข้าไป ฟังก์ชัน useEffect ก็จะถูกเรียกซ้ำๆๆๆๆ เพื่อหลีกเลี่ยงเหตุการณ์นี้ ควรจะใส่ Array เปล่า ๆ []
ป้องกันไว้เพื่อให้ useEffect ถูกเรียกใช้งานเฉพาะตอนที่ Mount/Unmount Component ครั้งเดียวเท่านั้น 😎
แล้วถ้าอยาก Update useEffect ให้มันทำงานอีกรอบล่ะ ก็ใส่ตัวแปรที่ต้องการเช็คว่า ถ้าตัวแปรพวกนี้มีการเปลี่ยนแปลงนะ ให้เรียกใช้งาน useEffect อีกครั้ง เช่น isActive และ seconds ในตัวอย่างข้างบน แค่นี้ useEffect ก็จะถูกเรียกเรื่อย ๆ เมื่อค่าที่อยู่ใน Array มีการเปลี่ยนแปลงแล้ว
นอกจากนี้เราสามารถทำการ Unmount ได้โดยการใส่ฟังก์ชันที่เราต้องการไปใน return
เพื่อให้ทำงานเหมือนกันกับ ฟังก์ชัน componentWillUnmount ที่กล่าวไปแล้วข้างต้น จากตัวอย่างก็คือ การ clearInterval(interval)
เพื่อเป็นการ Clean up ฟังก์ชัน 🤗
อธิบายง่าย ๆ คือ useEffect จะถูกเรียกใช้งานทุกครั้งที่มีการ Render โดยถ้าเราอยากให้ useEffect ทำงานแค่ครั้งเดียวหลัง render() ก็ใส่ Array เปล่า ๆ ไป โดยจากตัวอย่างข้างต้นก็สามารถเอา isActive และ seconds ออกเพื่อไม่ให้มีการ Trigger อัพเดทตัวแปรใด ๆ และไม่เกิดการ Update นั่นเอง ส่วน Updating จะเกิดขึ้นโดยที่ ฟังก์ชัน useEffect จะถูกเรียกใช้เรื่อย ๆ เมื่อค่าตัวแปร ใน Array เกิดการเปลี่ยนแปลงนั่นเอง
สุดท้ายเวลาจะ Unmount ก็ยัดฟังก์ชันที่ต้องการจะ Clean up ใส่ลงใน Return เป็นอันเสร็จ สำหรับการทำ Unmounting
Conclusion
โดยสรุปแล้ว useEffect ช่วยให้เราสามารถจัดการ Lifecycle ของ React แบบที่มีใน Class Component ได้ใน Functional Component (Hooks) ด้วยการเขียนฟังก์ชันที่ง่ายกว่า โดยการรวบเอาฟังก์ชัน componentDidMount, componentDidUpdate และ componentWillUnmount มาทำงานด้วยกัน ถ้าหากงานของเราไม่มีความซับซ้อนมากนักการใช้ useEffect มาช่วยก็จะทำให้ชีวิตง่ายขึ้นเยอะ แต่ถ้าฟังก์ชันเราซับซ้อนมากการใช้ useEffect ก็ควรเรียบเรียง Code ดี ๆ เพื่อไม่ให้ดูวุ่นวายเกินไปนะ 55555
Reference:
- React life cycle มันคืออะไร ???. วันนี้เราจะมาพูดถึง life cycle ของ… | by Like | Medium
- อธิบาย React Lifecycle แต่ละอันมีหน้าที่อย่างไร | by Nattawut Ruangvivattanaroj | โกคูส์ สตูดิโอ (igokuz.com)
ขอบคุณที่อ่านจนจบนะคะ หวังว่าจะเป็นประโยชน์น้าา