Demystifying React Hooks — useCallback

Dec 03 2022
ในบทความนี้ เราจะสำรวจว่าเมื่อใดและอย่างไรที่จะใช้ useCallback hook ของ React และข้อผิดพลาดที่เกิดขึ้นโดย Junior Developers ส่วนใหญ่
เริ่มต้นใช้งาน หากคุณต้องการติดตาม IDE ในเครื่องของคุณ คุณสามารถค้นหา GitHub Repo ได้ที่นี่ ความเท่าเทียมกันในการอ้างอิงเป็นแนวคิดพื้นฐานทั้งใน JavaScript และวิทยาการคอมพิวเตอร์โดยรวม

เริ่มต้นใช้งาน

หากคุณต้องการติดตามใน IDE ในพื้นที่ของคุณ คุณสามารถค้นหา GitHub Repo ได้ที่นี่

  • clone
  • cd client
  • npm i
  • npm start

ความเท่าเทียมกันในการอ้างอิงเป็นแนวคิดพื้นฐานทั้งใน JavaScript และวิทยาการคอมพิวเตอร์โดยรวม ดังนั้นเรามาเริ่มด้วยการสาธิตการทำงานจริง

ฉันได้ฝังภาพหน้าจอไว้ตลอดทั้งบทความเพื่อความสะดวกในการใช้งานบนมือถือ หากคุณอยู่บนเดสก์ท็อปและได้โคลนมันขึ้นมา ให้รันreferentialEquality.jsเพื่อสังเกตผลลัพธ์หรือเพียงแค่เล่นกับส่วนย่อยของ JSFiddle ที่ฝังอยู่ด้านล่าง

เมื่อประเมินว่า the integer 1เท่ากับอย่างเคร่งครัดหรือไม่integer 1คอนโซลจะพิมพ์ออกtrueมา นี่เป็นเพราะว่า อืม… the integer 1 นั้นเท่ากับ the integer 1.

จำนวนเต็มจะเท่ากันอย่างเคร่งครัด

เราเห็นผลลัพธ์เดียวกันเมื่อประเมินสองสตริง

สตริงมีความเท่าเทียมกันอย่างเคร่งครัด

เห็นได้ชัดว่า กรณีนี้จะเกิดขึ้นเสมอสำหรับข้อมูลดั้งเดิมสองประเภทที่มีค่าเท่ากัน

แล้วโครงสร้างข้อมูลล่ะ? ตัวอย่างเช่น ตัวอักษรอ็อบเจกต์สองตัวที่มีคู่คีย์/ค่าเดียวกัน? แล้วตัวอักษรวัตถุเปล่าล่ะ?

วัตถุไม่เท่ากันอย่างเคร่งครัด

จะพิมพ์ทำไมเนี่falseย เมื่อเปรียบเทียบว่าตัวอักษรของ วัตถุสองตัวนี้เท่ากันหรือไม่ JavaScript จะใช้ที่อยู่หน่วยความจำ ตามลำดับ

กล่าวอีกนัยหนึ่ง วัตถุทั้งสองนี้อาจมีค่าเหมือนกันแต่ไม่ได้อ้างอิงถึงวัตถุเดียวกัน มีลักษณะเหมือนกันแต่ใช้พื้นที่ต่างกันสองพื้นที่ในหน่วยความจำ

เช่นเดียวกันไม่ว่าคุณกำลังเปรียบเทียบตัวอักษรอ็อบเจกต์สองตัว ตัวหนังสืออาร์เรย์สองตัว หรือสองฟังก์ชัน!

อาร์เรย์ไม่เท่ากันอย่างเคร่งครัด

เพื่อแสดงสิ่งนี้เพิ่มเติม เราจะกำหนดฟังก์ชันfuncซึ่งจะส่งคืนฟังก์ชันที่ไม่ระบุชื่อ ซึ่งจะส่งคืนอย่างอื่น ( เช่น องค์ประกอบ JSX )

การสร้างส่วนประกอบการทำงานที่เสแสร้ง

จากนั้นเราจะกำหนดสองฟังก์ชันที่แตกต่างกันfirstRenderและsecondRenderเท่ากับค่าที่ส่งกลับfuncโดย

การกำหนดนิยามฟังก์ชันของเรา

ให้คิดว่าfuncเป็นองค์ประกอบการทำงานของ React ในขณะที่firstRenderเป็นฟังก์ชันที่อยู่ภายในในการเรนเดอร์ครั้งแรก และsecondRenderเป็นฟังก์ชันที่อยู่ภายในการเรนเดอร์ครั้งที่สอง

แม้ว่าfirstRenderและ ส่งคืนค่าเดียวกันและถูก กำหนดsecondRenderจากคำจำกัดความเดียวกัน แต่ก็ไม่มีความเท่าเทียมกันในการอ้างอิง ด้วยเหตุนี้ ทุกครั้งที่คอมโพเนนต์แสดงผล คอมโพเนนต์จะกำหนดฟังก์ชันนี้ใหม่

หน้าที่ของเราสองคนไม่เท่ากันโดยเด็ดขาด

น่าเสียดายที่ใน JavaScript นั้นไม่ง่ายเลยที่จะพิมพ์ที่อยู่หน่วยความจำเหล่านี้เหมือนใน Python แต่สำหรับคำอธิบายเชิงลึกของการอ้างอิงเทียบกับค่า โปรดดูที่บทความนี้จาก freeCodeCamp

หัวข้อนี้อาจหนาแน่น และคุณไม่จำเป็นต้องสอนในชั้นเรียนในคืนนี้ ดังนั้น สำหรับตอนนี้ โปรดจำไว้ว่า:

  • ประเภทข้อมูลดั้งเดิม===ประเภทข้อมูลดั้งเดิม
  • โครงสร้างข้อมูล!==โครงสร้างข้อมูล

รหัสเริ่มต้น

หลังจากที่เราหมุนแอปของเราแล้ว ให้เปิดBookDetails.jsxส่วนประกอบและบันทึกใหม่อีกครั้ง สิ่งแรกที่เราอาจสังเกตเห็นในเซิร์ฟเวอร์ React dev ของเรานั้นเป็นเรื่องปกติWARNINGที่นักพัฒนารุ่นใหม่มักเพิกเฉย เมื่อคุณเริ่มทำงานและเริ่มเขียนโค้ดสำหรับการผลิต linters ของคุณจะเข้มงวดยิ่งกว่าสิ่งที่มีอยู่ในcreate-react-appตัว WARNINGSจะหันไปหาERRORSและผู้ลบบางคนจะไม่อนุญาตให้คุณพุชก่อนที่คุณจะจัดการสิ่งเหล่าERRORSนี้

ดังนั้นแทนที่จะเพิกเฉย เรามาหาวิธีรักษากันดีกว่า

โซลูชันที่เสนอโดย React

หมายเหตุ: คุณอาจต้องบันทึกใหม่ก่อนBookDetails.jsxเพื่อสร้างสิ่งนี้WARNING

หากเราเจาะลึกลงไปในReact Docsเราสามารถถอดรหัสวิธีแก้ปัญหาที่เสนอกึ่งสับสนได้WARNINGดังต่อไปนี้:

1. รวมคำจำกัดความของฟังก์ชันไว้ในไฟล์useEffect.

  • เราไม่สามารถเรียกใช้ฟังก์ชันนี้ได้ที่อื่นเว้นแต่เราจะกำหนดใหม่
  • สิ่งนี้จะกระตุ้นuseEffect ทุกครั้งที่สถานะหรืออุปกรณ์ประกอบฉากเปลี่ยนแปลง บางครั้งทำให้เกิดการเรนเดอร์ซ้ำไม่สิ้นสุด และในกรณีของเรา เนื่องจากเราเรียกใช้ฟังก์ชัน state setter หลังจากเรียก API จึงอาจทำให้ API ของเราโหลดมากเกินไปด้วยคำขอปลายทางที่ไม่มีที่สิ้นสุด
  • ฟังก์ชันจะไม่ถูกเรียกใช้
  • ครั้งแรกที่คอมโพเนนต์แสดงผล มันจะกำหนดฟังก์ชันของเรา ซึ่งจะทริกเกอร์ ซึ่งจะuseEffectทำให้คอมโพเนนต์แสดงผลใหม่ ซึ่งจะกำหนดฟังก์ชันใหม่ ซึ่งจะทริกเกอร์useEffectซึ่งจะทำให้คอมโพเนนต์แสดงผลใหม่ ซึ่ง จะกำหนดฟังก์ชันใหม่…

วิธีที่ง่ายที่สุดและต้องการคือ 'รวมไว้' นั่นคือย้ายgetBookDetailsคำจำกัดความของฟังก์ชันภายในไฟล์useEffect. สิ่งนี้เป็นไปตามหลักการเขียนโปรแกรมเชิงวัตถุที่เรียกว่าEncapsulation

แต่สมมติว่าเรารู้ว่าเราต้องเรียกใช้ฟังก์ชันที่อื่น เราควรกำหนดใหม่ในภายหลังหรือไม่? ที่ไม่แห้งมากของเรา

มาเปลี่ยนอาร์เรย์การขึ้นต่อกันเพื่อรวมการอ้างอิงฟังก์ชันของเรา ตอนนี้ คุณuseEffectควรมีลักษณะเช่นนี้

รวมถึงฟังก์ชันของเราในอาร์เรย์การพึ่งพา

และgetBookDetailsยังคงกำหนดไว้เหนือ .useEffect

นิยามดั้งเดิมของฟังก์ชันของเรา

ตอนนี้เรามีใหม่WARNING

การกำหนดฟังก์ชั่นของเรานอก useEffect ในขณะที่รวมไว้ในอาร์เรย์การพึ่งพาจะทำให้เกิดการแสดงผลซ้ำไม่สิ้นสุด

เข้าสู่ useCallback Hook

ในระยะสั้นuseCallbackhook ช่วยให้คุณสามารถแคชหรือ 'บันทึก' ฟังก์ชันระหว่างการแสดงผลซ้ำของส่วนประกอบของคุณ มันทำงานคล้ายกับuseMemoความแตกต่างที่เราจะพูดถึงในบทความอื่น

หากคุณสนใจเกี่ยวกับสิ่งนี้ คุณสามารถอ่านเพิ่มเติมได้ในReact docs

โปรดสังเกตคำเตือน:

คุณควรพึ่งพาuseCallbackการเพิ่มประสิทธิภาพ เท่านั้น หากโค้ดของคุณใช้งานไม่ได้ ให้ค้นหาปัญหาพื้นฐานและแก้ไขก่อน จากนั้นคุณอาจเพิ่มuseCallbackเพื่อปรับปรุงประสิทธิภาพ

useCallbackไวยากรณ์

useCallbackไวยากรณ์ของ ' คล้ายกับuseEffectไวยากรณ์ของ ' ที่เรารู้อยู่แล้ว ดูโครงกระดูกของแต่ละคน

ตะขอทั้งสองมีโครงร่างวากยสัมพันธ์ที่เหมือนกัน

ข้อแตกต่างเล็กน้อยคือ กับuseEffectเราบอกให้ฟังก์ชันนิรนามดำเนินการฟังก์ชันของเราขณะที่กับuseCallbackเรากำหนดค่าที่ส่งกลับ ให้กับการอ้างอิงที่จะเรียกที่อื่น

การใช้ useCallback

ก่อนอื่นเราจะนำเข้าuseCallbackจาก'react'. แทนที่จะเพิ่มบรรทัดใหม่ วิธีที่ดีที่สุดคือทำลายมันพร้อมกับการนำเข้าอื่นๆ ของเรา

รายการที่แยกโครงสร้างจากแพ็คเกจเดียวกันควรนำเข้าในบรรทัดเดียวกัน

ตอนนี้เราสามารถกำหนดgetBookDetailsค่าที่ส่งคืนจากuseCallbackการเรียกใช้ฟังก์ชัน

กำหนดผลตอบแทนของ useCallback ให้เป็นข้อมูลอ้างอิงของเรา

จากนั้นเราจะเพิ่มไวยากรณ์ทั้งหมดสำหรับuseCallback. จำอาร์เรย์การพึ่งพาของคุณ!

กรอกโครงกระดูกของ useCallback

ในตัวอย่างของเรา เราต้องการasyncก่อนพารามิเตอร์ของเรา

เพิ่ม async

และสุดท้าย เราเพิ่มตรรกะของฟังก์ชันของเราลงในบล็อกโค้ด

เพิ่มตรรกะของเราเพื่อใช้บล็อกโค้ดของ Callback

เมื่อเราบันทึก เราจะได้… WARNINGอีก

ผลตอบแทนของ useCallback ขึ้นอยู่กับค่าของ id

เหตุใดอาร์เรย์การพึ่งพาของเราควรติดตามidตัวแปร

ลองคิดดูให้ดี

  • หากค่าidเปลี่ยนแปลงgetBookDetailsต้องไปถึงจุดสิ้นสุดอื่น ดังนั้น React ควรกำหนดใหม่ คำจำกัดความของgetBookDetailsตัวอักษรขึ้นอยู่กับค่าidของ
เบ็ดเสร็จทั้งสองรุ่น

และในที่สุดก็ถึงซะที! เราเห็นสีเขียวในเซิร์ฟเวอร์ React dev ของเรา linter ที่มีความสุขคือ Senior Developer ที่มีความสุข และนักพัฒนาอาวุโสที่มีความสุขก็คือคุณที่มีความสุข!

ฉันมักจะมองหาเพื่อนและเพื่อนร่วมงานใหม่ๆ หากคุณพบว่าบทความนี้มีประโยชน์และต้องการเชื่อมต่อ คุณสามารถพบฉันที่บ้านใดก็ได้บนเว็บ

GitHub | ทวิตเตอร์ | LinkedIn | เว็บไซต์

ทรัพยากร

  • ความเท่าเทียมกันในการอ้างอิง
  • ประเภทข้อมูลดั้งเดิมของ JavaScript เทียบกับโครงสร้างข้อมูล
  • การห่อหุ้ม
  • useCallback
  • ตอบโต้เอกสาร