hooks ของ React เป็นคุณสมบัติที่ปรากฏหลังไฟเบอร์ หลายคนจึงเข้าใจผิดว่า hooks ต้องอาศัยไฟเบอร์จึงจะถูกนำมาใช้ จริงๆ แล้วทั้งสองอย่างนี้ไม่จำเป็นต้องเชื่อมต่อกัน
ตอนนี้ hooks ไม่เพียงถูกนำไปใช้ในการตอบสนองเท่านั้น แต่ยังรวมถึงในเฟรมเวิร์กเช่น preact, react ssr และกึ่งกลางอีกด้วย
มาดูกันว่า hooks ในเฟรมเวิร์กต่างๆ เหล่านี้ถูกนำไปใช้อย่างไร:
React อธิบายอินเทอร์เฟซผ่าน jsx ซึ่งจะถูกคอมไพล์เป็นฟังก์ชันการเรนเดอร์โดยเครื่องมือการคอมไพล์ เช่น babel หรือ tsc จากนั้นจึงดำเนินการเพื่อสร้าง vdom:
ฟังก์ชันการเรนเดอร์ที่นี่คือ React.createElement ก่อน React17:
หลังจาก React 17 ก็เปลี่ยนเป็น jsx:
รันไทม์ jsx นี้จะถูกนำเสนอโดยอัตโนมัติ และไม่จำเป็นต้องเก็บการนำเข้า React สำหรับแต่ละองค์ประกอบเหมือนเมื่อก่อน
การดำเนินการฟังก์ชัน Render สร้าง vdom:
โครงสร้างของ vdom เป็นดังนี้:
ก่อน React16 vdom นี้จะแสดงผลแบบวนซ้ำ โดยเพิ่ม ลบ และแก้ไข dom จริง
หลังจากที่ React16 เปิดตัวสถาปัตยกรรมไฟเบอร์ มีขั้นตอนเพิ่มเติม: ขั้นแรกแปลง vdom เป็นไฟเบอร์ จากนั้นเรนเดอร์ไฟเบอร์
กระบวนการแปลง vdom เป็นไฟเบอร์เรียกว่า reconcile และกระบวนการสุดท้ายของการเพิ่ม ลบ และแก้ไข dom จริงเรียกว่า commit
เหตุใดเราจึงต้องเปลี่ยนใจเลื่อมใสเช่นนี้?
เนื่องจาก vdom มีการอ้างอิงถึงโหนดย่อยของโหนดลูกเท่านั้น และไม่มีการอ้างอิงถึงโหนดพาเรนต์ของโหนดหลักและโหนดพี่น้องอื่นๆ ส่งผลให้จำเป็นต้องแสดงโหนด vdom ทั้งหมดไปยัง dom ในคราวเดียวแบบเรียกซ้ำโดยไม่ขัดจังหวะ
จะเกิดอะไรขึ้นถ้ามันถูกขัดจังหวะ? เนื่องจากโหนดพาเรนต์และโหนดพี่น้องไม่ได้รับการบันทึก เราจึงสามารถประมวลผลโหนดย่อยต่อไปได้เท่านั้น แต่ไม่สามารถประมวลผลส่วนอื่นๆ ของ vdom ได้
นั่นเป็นสาเหตุที่ React แนะนำโครงสร้างไฟเบอร์ประเภทนี้ ซึ่งมีการอ้างอิง เช่น การส่งคืนโหนดพาเรนต์, ลูกโหนดย่อย, โหนดพี่น้องพี่น้อง ฯลฯ ซึ่งสามารถถูกขัดจังหวะได้ เนื่องจากโหนดที่ยังไม่ได้ประมวลผลทั้งหมดสามารถพบได้หลังจากการหยุดชะงักและการกู้คืน
โครงสร้างของโหนดไฟเบอร์มีดังนี้:
กระบวนการนี้สามารถถูกขัดจังหวะได้ และแน่นอนว่าสามารถกำหนดเวลาได้ ซึ่งเป็นกระบวนการตามกำหนดการ
ดังนั้น สถาปัตยกรรมไฟเบอร์จึงแบ่งออกเป็นสามขั้นตอน: schdule, ปรับยอด (แปลง vdom เป็นไฟเบอร์) และคอมมิต (อัปเดตเป็น dom)
Hooks สามารถใช้ในส่วนประกอบของฟังก์ชันเพื่อเข้าถึงค่าบางค่าได้ และค่าเหล่านี้จะถูกเก็บไว้ในโหนดไฟเบอร์
ตัวอย่างเช่น มีการใช้ 6 hooks ในส่วนประกอบฟังก์ชันนี้:
จากนั้นจะมีรายการเชื่อมโยง memorizedState ของ 6 องค์ประกอบบนโหนดไฟเบอร์ที่เกี่ยวข้อง:
เชื่อมต่อกันโดยถัดไป:
hooks ที่แตกต่างกันเข้าถึงค่าในองค์ประกอบต่าง ๆ ของรายการที่เชื่อมโยง memorizedState นี่คือหลักการของ hooks ปฏิกิริยา
รายการที่เชื่อมโยงนี้มีขั้นตอนการสร้างและขั้นตอนการอัปเดต ดังนั้นคุณจะพบว่าการใช้งานขั้นสุดท้ายของ useXxx แบ่งออกเป็น mountXxx และ updateXxx:
ขั้นตอนการเมานท์ที่นี่คือการสร้างโหนด hook และประกอบเข้าด้วยกันเป็นรายการที่เชื่อมโยง:
รายการเชื่อมโยง hook ที่สร้างขึ้นจะเชื่อมโยงกับแอตทริบิวต์ memorizedState ของโหนดไฟเบอร์
เมื่อทำการอัพเดต คุณสามารถเรียกข้อมูลรายการ hook นี้ได้จากโหนดไฟเบอร์:
ด้วยวิธีนี้ ในการเรนเดอร์หลายครั้ง useXxx api สามารถค้นหา memorizedState ที่สอดคล้องกันบนไฟเบอร์โหนด
นี่คือหลักการของ React hooks คุณจะเห็นว่ามันเก็บ hook ไว้บนโหนดไฟเบอร์
แล้ว preact ต่างกันอย่างไร?
Preact เป็นเฟรมเวิร์กที่มีน้ำหนักเบากว่าซึ่งเข้ากันได้กับโค้ดการโต้ตอบ โดยรองรับส่วนประกอบของคลาสและส่วนประกอบของฟังก์ชัน รวมถึงฟีเจอร์การโต้ตอบ เช่น hooks อย่างไรก็ตาม ไม่ได้ใช้สถาปัตยกรรมไฟเบอร์
เนื่องจากส่วนใหญ่จะพิจารณาขนาดสูงสุด (เพียง 3kb) ไม่ใช่ประสิทธิภาพสูงสุด
เราเพิ่งเรียนรู้ว่า react เก็บรายการ hook ไว้บนโหนดไฟเบอร์ ถ้า preact ไม่มีโหนดไฟเบอร์ รายการ hook จะถูกเก็บไว้ที่ไหน
ในความเป็นจริง มันง่ายที่จะคิดว่าไฟเบอร์จะปรับเปลี่ยน vdom เพื่อปรับปรุงประสิทธิภาพเท่านั้น และไม่มีความแตกต่างที่สำคัญจาก vdom แล้วเราจะเก็บ hook ไว้บน vdom ได้หรือไม่
อันที่จริง preact จะวางรายการเบ็ดไว้บน vdom
ตัวอย่างเช่น ส่วนประกอบฟังก์ชันนี้มี 4 hooks:
การใช้งานคือการเข้าถึง hook ที่เกี่ยวข้องบน vdom:
มันไม่ได้แบ่ง hook ออกเป็นสองขั้นตอน เมานต์และอัปเดต เช่นเดียวกับการตอบสนอง แต่รวมเข้าด้วยกันเพื่อการประมวลผล
ดังแสดงในรูป มันเก็บ hooks ไว้ในอาร์เรย์ของ component.__hooks และเข้าถึงได้ผ่านทางตัวห้อย
องค์ประกอบนี้เป็นแอตทริบิวต์บน vdom:
นั่นคือค่าของ hooks จะถูกจัดเก็บไว้ในอาร์เรย์ของ vnode._component._hooks
เปรียบเทียบความแตกต่างระหว่าง react และ preact ในการใช้ hooks:
ใน react รายการ hook จะถูกจัดเก็บไว้ในแอตทริบิวต์ fiberNode.memorizedState ใน preact รายการ hook จะถูกจัดเก็บไว้ในแอตทริบิวต์
vnode._component._hooks ผ่านรายการถัดไปและใน preact รายการเชื่อมโยงของ hook คืออาร์เรย์
React จะแยกการสร้างและอัปเดตรายการเชื่อมโยงของ hook
การใช้งาน hooks จึงไม่อาศัยไฟเบอร์ เพียงแต่ต้องหาที่เก็บข้อมูล hook ที่สอดคล้องกับส่วนประกอบนั้น ตราบใดที่สามารถดึงข้อมูลได้ในระหว่างการเรนเดอร์ ก็ไม่สำคัญว่าจะเก็บไว้ที่ใด
เนื่องจากการเรนเดอร์ vdom, ไฟเบอร์ และส่วนประกอบมีความสัมพันธ์กันอย่างมาก จึงถูกจัดเก็บไว้ในโครงสร้างเหล่านี้
ตัวอย่างเช่น เมื่อ react ssr ใช้ hooks มันจะไม่มีอยู่บนไฟเบอร์หรือบน vdom:
อันที่จริง นอกเหนือจาก csr แล้ว แพคเกจ react-dom ยังสามารถทำ ssr ได้อีกด้วย:
ใช้วิธี render ของ react- dom เมื่อ Csr:
เมื่อ ssr ให้ใช้เมธอด renderToString หรือเมธอด renderToStream ของ react-dom/server:
คุณคิดว่าการแปลง vdom เป็นไฟเบอร์จะเสร็จสิ้นในช่วง ssr หรือไม่?
ไม่แน่นอน Fiber เป็นโครงสร้างที่แนะนำเพื่อปรับปรุงประสิทธิภาพการเรนเดอร์เมื่อทำงานในเบราว์เซอร์ ทำให้การคำนวณหยุดชะงัก และทำการคำนวณเมื่อไม่ได้ใช้งาน
โดยปกติแล้วการเรนเดอร์ฝั่งเซิร์ฟเวอร์ไม่จำเป็นต้องใช้ไฟเบอร์
ถ้าไม่จำเป็นต้องใช้ไฟเบอร์ จะเก็บ hook list ไว้ที่ไหน? วดอม?
มันสามารถวางใน vdom ได้จริง แต่ไม่ใช่
ตัวอย่างเช่น useRef hooks:
เป็นรายการที่เชื่อมโยงซึ่งเชื่อมติดกับรายการถัดไปโดยเริ่มจาก firstWorkInProgressHook
และ firstWorkInProgressHook เป็นโหนด hook แรกที่สร้างขึ้นด้วย createHook:
มันไม่ได้เมานท์บน vdom
ทำไม
เนื่องจาก ssr จำเป็นต้องแสดงผลเพียงครั้งเดียวและไม่จำเป็นต้องอัปเดต จึงไม่จำเป็นต้องวางมันไว้บน vdom
เพียงล้างรายการ hook ทุกครั้งที่คุณประมวลผล hooks ของแต่ละส่วนประกอบเสร็จแล้ว:
ดังนั้นเมื่อใช้ react ssr จะมี hooks อยู่ในตัวแปรโกลบอล
เปรียบเทียบความแตกต่างในหลักการใช้งานของ hooks ใน react csr และ ssr:
ใน csr ไฟเบอร์จะถูกสร้างขึ้นจาก vdom ซึ่งใช้เพื่อทำให้การเรนเดอร์ขัดจังหวะและปรับปรุงประสิทธิภาพผ่านการตั้งเวลาที่ไม่ได้ใช้งาน แต่ใน ssr จะไม่ถูกเรนเดอร์โดยตรง vdom เมื่อใช้
csr hooks จะถูกบันทึกลงในโหนดไฟเบอร์ ในขณะที่ใช้ ssr พวกมันจะถูกวางไว้บนตัวแปรโกลบอลโดยตรง และจะถูกล้างหลังจากแต่ละส่วนประกอบถูกประมวลผล เนื่องจาก CSR จะไม่ถูกใช้เป็นครั้งที่สอง
การสร้างและอัปเดต hooks จะถูกแบ่งออกเป็นสองขั้นตอน: เมานต์และอัปเดต ในขณะที่ SSR จะถูกประมวลผลเพียงครั้งเดียว และเฉพาะขั้นตอนการสร้างเท่านั้น
จริงๆ แล้วหลักการใช้งานของ hooks นั้นไม่ซับซ้อน นั่นคือในบริบทบางอย่าง จัดเก็บรายการที่เชื่อมโยงไว้ในรายการที่เชื่อมโยง จากนั้น hooks api จะเข้าถึงข้อมูลที่เกี่ยวข้องจากองค์ประกอบต่างๆ ของรายการที่เชื่อมโยงเพื่อทำให้ตรรกะของตนสมบูรณ์ บริบทนี้อาจเป็น vdom, ไฟเบอร์ หรือแม้แต่ตัวแปรโกลบอล
อย่างไรก็ตาม แนวคิดของ hooks ยังคงได้รับความนิยมอย่างมาก
เป็นเฟรมเวิร์ก Node.js:
เฟรมเวิร์กฝั่งเซิร์ฟเวอร์โดยธรรมชาติแล้วไม่มีโครงสร้างเช่น vdom และไฟเบอร์ แต่แนวคิดของ hooks ไม่ได้ขึ้นอยู่กับสิ่งเหล่านี้ ในการใช้ hooks API คุณจะต้องวางรายการที่เชื่อมโยงในบริบทที่แน่นอนเท่านั้น
Midway ใช้ API ที่คล้ายกับ React hooks:
ฉันไม่ได้ดูเจาะจงว่ามี hook list อยู่ที่ไหน แต่เราเข้าใจหลักการใช้งานของ hooks แล้ว ตราบใดที่มีบริบทในการจัดเก็บ hook list ก็สามารถอยู่ที่ไหนก็ได้
React hooks เป็นคุณลักษณะที่เกิดขึ้นหลังจากสถาปัตยกรรม React Fiber หลายๆ คนเข้าใจผิดว่าต้องใช้ Hooks กับ Fiber เราดูที่การใช้งาน Hooks ใน React, Preact, React ssr และ Midway ตามลำดับ และพบว่า นี่ไม่ใช่กรณี:
hook จะไม่เป็นไร แล้ว React hooks จะต้องอาศัยไฟเบอร์ในการนำไปใช้หรือไม่?
ไม่แน่นอน มันสามารถใช้ได้กับไฟเบอร์, vdom, ตัวแปรโกลบอล หรือแม้แต่บริบทใดๆ