ไทย

เรียนรู้วิธีใช้รูปแบบ React Context Selector เพื่อปรับปรุง re-render และเพิ่มประสิทธิภาพในแอปพลิเคชัน React ของคุณ ตัวอย่างการใช้งานจริงและแนวทางปฏิบัติที่ดีที่สุดระดับโลกรวมอยู่ด้วย

รูปแบบ React Context Selector: การปรับปรุง Re-render เพื่อประสิทธิภาพ

React Context API เป็นวิธีที่มีประสิทธิภาพในการจัดการสถานะส่วนกลางในแอปพลิเคชันของคุณ อย่างไรก็ตาม ความท้าทายทั่วไปเกิดขึ้นเมื่อใช้ Context: การ re-render ที่ไม่จำเป็น เมื่อค่า Context เปลี่ยนแปลง คอมโพเนนต์ทั้งหมดที่ใช้ Context นั้นจะ re-render แม้ว่าคอมโพเนนต์เหล่านั้นจะขึ้นอยู่กับข้อมูล Context เพียงเล็กน้อยก็ตาม สิ่งนี้สามารถนำไปสู่ปัญหาคอขวดด้านประสิทธิภาพ โดยเฉพาะอย่างยิ่งในแอปพลิเคชันขนาดใหญ่และซับซ้อน รูปแบบ Context Selector นำเสนอโซลูชันโดยอนุญาตให้คอมโพเนนต์สมัครรับเฉพาะส่วนที่ต้องการของ Context เท่านั้น ซึ่งช่วยลดการ re-render ที่ไม่จำเป็นได้อย่างมาก

ทำความเข้าใจปัญหา: การ Re-render ที่ไม่จำเป็น

มาอธิบายเรื่องนี้ด้วยตัวอย่าง ลองนึกภาพแอปพลิเคชันอีคอมเมิร์ซที่จัดเก็บข้อมูลผู้ใช้ (ชื่อ, อีเมล, ประเทศ, การตั้งค่าภาษา, รายการในรถเข็น) ใน Context provider หากผู้ใช้อัปเดตการตั้งค่าภาษา คอมโพเนนต์ทั้งหมดที่ใช้ Context รวมถึงคอมโพเนนต์ที่แสดงเฉพาะชื่อผู้ใช้ จะ re-render สิ่งนี้ไม่มีประสิทธิภาพและอาจส่งผลกระทบต่อประสบการณ์ของผู้ใช้ พิจารณาผู้ใช้ในสถานที่ทางภูมิศาสตร์ที่แตกต่างกัน หากผู้ใช้ชาวอเมริกันอัปเดตโปรไฟล์ของตน คอมโพเนนต์ที่แสดงรายละเอียดของผู้ใช้ชาวยุโรป *ไม่ควร* re-render

เหตุใดการ Re-render จึงมีความสำคัญ

ขอแนะนำรูปแบบ Context Selector

รูปแบบ Context Selector แก้ปัญหาการ re-render ที่ไม่จำเป็นโดยอนุญาตให้คอมโพเนนต์สมัครรับเฉพาะส่วนที่ต้องการของ Context เท่านั้น ทำได้โดยใช้ฟังก์ชัน selector ที่ดึงข้อมูลที่จำเป็นจากค่า Context เมื่อค่า Context เปลี่ยนแปลง React จะเปรียบเทียบผลลัพธ์ของฟังก์ชัน selector หากข้อมูลที่เลือกไม่เปลี่ยนแปลง (โดยใช้ความเท่าเทียมกันอย่างเคร่งครัด ===) คอมโพเนนต์จะไม่ re-render

วิธีการทำงาน

  1. กำหนด Context: สร้าง React Context โดยใช้ React.createContext()
  2. สร้าง Provider: ห่อแอปพลิเคชันหรือส่วนที่เกี่ยวข้องของคุณด้วย Context Provider เพื่อให้ค่า Context พร้อมใช้งานสำหรับลูก ๆ
  3. ใช้ Selectors: กำหนดฟังก์ชัน selector ที่ดึงข้อมูลเฉพาะจากค่า Context ฟังก์ชันเหล่านี้เป็นแบบ pure และควรคืนค่าเฉพาะข้อมูลที่จำเป็นเท่านั้น
  4. ใช้ Selector: ใช้ custom hook (หรือไลบรารี) ที่ใช้ประโยชน์จาก useContext และฟังก์ชัน selector ของคุณเพื่อดึงข้อมูลที่เลือกและสมัครรับการเปลี่ยนแปลงเฉพาะในข้อมูลนั้น

การใช้รูปแบบ Context Selector

ไลบรารีและการใช้งานแบบกำหนดเองหลายอย่างสามารถอำนวยความสะดวกให้กับรูปแบบ Context Selector ลองสำรวจแนวทางทั่วไปโดยใช้ custom hook

ตัวอย่าง: Context ผู้ใช้แบบง่าย

พิจารณา user context ที่มีโครงสร้างดังต่อไปนี้:

const UserContext = React.createContext({ name: 'John Doe', email: 'john.doe@example.com', country: 'USA', language: 'en', theme: 'light' });

1. การสร้าง Context

const UserContext = React.createContext({ name: 'John Doe', email: 'john.doe@example.com', country: 'USA', language: 'en', theme: 'light' });

2. การสร้าง Provider

const UserProvider = ({ children }) => { const [user, setUser] = React.useState({ name: 'John Doe', email: 'john.doe@example.com', country: 'USA', language: 'en', theme: 'light' }); const updateUser = (updates) => { setUser(prevUser => ({ ...prevUser, ...updates })); }; const value = React.useMemo(() => ({ user, updateUser }), [user]); return ( {children} ); };

3. การสร้าง Custom Hook ด้วย Selector

import React from 'react'; function useUserContext() { const context = React.useContext(UserContext); if (!context) { throw new Error('useUserContext must be used within a UserProvider'); } return context; } function useUserSelector(selector) { const context = useUserContext(); const [selected, setSelected] = React.useState(() => selector(context.user)); React.useEffect(() => { setSelected(selector(context.user)); // Initial selection const unsubscribe = context.updateUser; return () => {}; // No actual unsubscription needed in this simple example, see below for memoizing. }, [context.user, selector]); return selected; }

หมายเหตุสำคัญ: `useEffect` ด้านบนขาดการ memoization ที่เหมาะสม เมื่อ `context.user` เปลี่ยนแปลง มันจะรันซ้ำ *เสมอ* แม้ว่าค่าที่เลือกจะเหมือนกันก็ตาม สำหรับ selector ที่แข็งแกร่งและ memoized โปรดดูส่วนถัดไปหรือไลบรารีเช่น `use-context-selector`

4. การใช้ Selector Hook ในคอมโพเนนต์

function UserName() { const name = useUserSelector(user => user.name); return

Name: {name}

; } function UserEmail() { const email = useUserSelector(user => user.email); return

Email: {email}

; } function UserCountry() { const country = useUserSelector(user => user.country); return

Country: {country}

; }

ในตัวอย่างนี้ คอมโพเนนต์ UserName, UserEmail และ UserCountry จะ re-render เฉพาะเมื่อข้อมูลเฉพาะที่พวกเขาเลือก (ชื่อ, อีเมล, ประเทศ ตามลำดับ) เปลี่ยนแปลง หากการตั้งค่าภาษาของผู้ใช้ได้รับการอัปเดต คอมโพเนนต์เหล่านี้จะ *ไม่* re-render ซึ่งนำไปสู่การปรับปรุงประสิทธิภาพที่สำคัญ

การ Memoizing Selectors และ Values: สิ่งจำเป็นสำหรับการเพิ่มประสิทธิภาพ

เพื่อให้รูปแบบ Context Selector มีประสิทธิภาพอย่างแท้จริง การ memoization เป็นสิ่งสำคัญ หากไม่มี การทำงาน selector อาจคืนค่าอ็อบเจ็กต์หรืออาร์เรย์ใหม่แม้ว่าข้อมูลพื้นฐานจะไม่เปลี่ยนแปลงในเชิงความหมาย ซึ่งนำไปสู่การ re-render ที่ไม่จำเป็น ในทำนองเดียวกัน การตรวจสอบให้แน่ใจว่าค่า provider ก็ได้รับการ memoized ก็มีความสำคัญเช่นกัน

การ Memoizing ค่า Provider ด้วย useMemo

Hook useMemo สามารถใช้เพื่อ memoize ค่าที่ส่งไปยัง UserContext.Provider สิ่งนี้ทำให้มั่นใจได้ว่าค่า provider จะเปลี่ยนแปลงเฉพาะเมื่อ dependencies พื้นฐานเปลี่ยนแปลง

const UserProvider = ({ children }) => { const [user, setUser] = React.useState({ name: 'John Doe', email: 'john.doe@example.com', country: 'USA', language: 'en', theme: 'light' }); const updateUser = (updates) => { setUser(prevUser => ({ ...prevUser, ...updates })); }; // Memoize the value passed to the provider const value = React.useMemo(() => ({ user, updateUser }), [user, updateUser]); return ( {children} ); };

การ Memoizing Selectors ด้วย useCallback

หากฟังก์ชัน selector ถูกกำหนด inline ภายในคอมโพเนนต์ ฟังก์ชันเหล่านั้นจะถูกสร้างขึ้นใหม่ในทุก render แม้ว่าจะเป็นฟังก์ชันเดียวกันในเชิงตรรกะก็ตาม สิ่งนี้สามารถเอาชนะจุดประสงค์ของรูปแบบ Context Selector ได้ เพื่อป้องกันสิ่งนี้ ให้ใช้ hook useCallback เพื่อ memoize ฟังก์ชัน selector

function UserName() { // Memoize the selector function const nameSelector = React.useCallback(user => user.name, []); const name = useUserSelector(nameSelector); return

Name: {name}

; }

การเปรียบเทียบเชิงลึกและโครงสร้างข้อมูลที่ไม่เปลี่ยนรูป

สำหรับสถานการณ์ที่ซับซ้อนมากขึ้น โดยที่ข้อมูลภายใน Context นั้นซ้อนกันอยู่ลึก ๆ หรือมีอ็อบเจ็กต์ที่เปลี่ยนแปลงได้ ให้พิจารณาใช้โครงสร้างข้อมูลที่ไม่เปลี่ยนรูป (เช่น Immutable.js, Immer) หรือใช้ฟังก์ชันเปรียบเทียบเชิงลึกใน selector ของคุณ สิ่งนี้ทำให้มั่นใจได้ว่าการเปลี่ยนแปลงจะถูกตรวจพบอย่างถูกต้อง แม้ว่าอ็อบเจ็กต์พื้นฐานจะถูกเปลี่ยนแปลงในสถานที่ก็ตาม

ไลบรารีสำหรับรูปแบบ Context Selector

ไลบรารีหลายแห่งมีโซลูชันสำเร็จรูปสำหรับการใช้งานรูปแบบ Context Selector ทำให้กระบวนการง่ายขึ้นและนำเสนอคุณสมบัติเพิ่มเติม

use-context-selector

use-context-selector เป็นไลบรารีที่ได้รับความนิยมและมีการดูแลรักษาอย่างดีซึ่งออกแบบมาโดยเฉพาะเพื่อจุดประสงค์นี้ นำเสนอวิธีที่ง่ายและมีประสิทธิภาพในการเลือกค่าเฉพาะจาก Context และป้องกันการ re-render ที่ไม่จำเป็น

การติดตั้ง:

npm install use-context-selector

การใช้งาน:

import { useContextSelector } from 'use-context-selector'; function UserName() { const name = useContextSelector(UserContext, user => user.name); return

Name: {name}

; }

Valtio

Valtio เป็นไลบรารีการจัดการสถานะที่ครอบคลุมมากขึ้น ซึ่งใช้พร็อกซีสำหรับการอัปเดตสถานะที่มีประสิทธิภาพและการ re-render แบบเลือกได้ นำเสนอแนวทางที่แตกต่างในการจัดการสถานะ แต่สามารถใช้เพื่อให้ได้ประโยชน์ด้านประสิทธิภาพที่คล้ายคลึงกับรูปแบบ Context Selector

ประโยชน์ของรูปแบบ Context Selector

เมื่อใดควรใช้รูปแบบ Context Selector

รูปแบบ Context Selector มีประโยชน์อย่างยิ่งในสถานการณ์ต่อไปนี้:

ทางเลือกอื่นสำหรับรูปแบบ Context Selector

แม้ว่ารูปแบบ Context Selector จะเป็นเครื่องมือที่มีประสิทธิภาพ แต่ก็ไม่ใช่ทางออกเดียวสำหรับการเพิ่มประสิทธิภาพการ re-render ใน React ต่อไปนี้เป็นแนวทางอื่น ๆ:

ข้อควรพิจารณาสำหรับแอปพลิเคชันระดับโลก

เมื่อพัฒนาแอปพลิเคชันสำหรับผู้ชมทั่วโลก ให้พิจารณาปัจจัยต่อไปนี้เมื่อใช้งานรูปแบบ Context Selector:

สรุป

รูปแบบ React Context Selector เป็นเทคนิคที่มีค่าสำหรับการเพิ่มประสิทธิภาพการ re-render และปรับปรุงประสิทธิภาพในแอปพลิเคชัน React การอนุญาตให้คอมโพเนนต์สมัครรับเฉพาะส่วนที่ต้องการของ Context เท่านั้น คุณสามารถลดการ re-render ที่ไม่จำเป็นได้อย่างมากและสร้างอินเทอร์เฟซผู้ใช้ที่ตอบสนองและมีประสิทธิภาพมากขึ้น อย่าลืม memoize selector และค่า provider ของคุณเพื่อการเพิ่มประสิทธิภาพสูงสุด พิจารณาไลบรารีเช่น use-context-selector เพื่อลดความซับซ้อนในการใช้งาน เมื่อคุณสร้างแอปพลิเคชันที่ซับซ้อนมากขึ้น การทำความเข้าใจและการใช้เทคนิคเช่นรูปแบบ Context Selector จะมีความสำคัญต่อการรักษาประสิทธิภาพและมอบประสบการณ์การใช้งานที่ยอดเยี่ยม โดยเฉพาะอย่างยิ่งสำหรับผู้ชมทั่วโลก