คู่มือฉบับสมบูรณ์สำหรับการปรับปรุง Context API ของ React โดยใช้ useContext เพื่อเพิ่มประสิทธิภาพและความสามารถในการปรับขนาดในแอปพลิเคชันขนาดใหญ่
React useContext: ปรับปรุงประสิทธิภาพการใช้ Context API
Context API ของ React ซึ่งเข้าถึงได้หลักๆ ผ่าน hook useContext เป็นกลไกอันทรงพลังสำหรับการแชร์ข้อมูลทั่วทั้ง tree คอมโพเนนต์ของคุณ โดยไม่จำเป็นต้องส่ง props ลงไปในทุกระดับด้วยตนเอง แม้ว่าสิ่งนี้จะอำนวยความสะดวกได้อย่างมาก แต่การใช้งานที่ไม่เหมาะสมอาจนำไปสู่คอขวดด้านประสิทธิภาพ โดยเฉพาะอย่างยิ่งในแอปพลิเคชันขนาดใหญ่และซับซ้อน คู่มือนี้จะเจาะลึกกลยุทธ์ที่มีประสิทธิภาพในการปรับปรุงการใช้ Context API โดยใช้ useContext เพื่อให้แน่ใจว่าแอปพลิเคชัน React ของคุณยังคงมีประสิทธิภาพและปรับขนาดได้
ทำความเข้าใจถึงหลุมพรางด้านประสิทธิภาพที่อาจเกิดขึ้น
ปัญหาหลักอยู่ที่วิธีที่ useContext ทริกเกอร์การแสดงผลซ้ำ เมื่อคอมโพเนนต์ใช้ useContext จะสมัครรับการเปลี่ยนแปลงภายในบริบทที่ระบุ การอัปเดตใดๆ ในค่าของบริบท โดยไม่คำนึงว่าคอมโพเนนต์เฉพาะนั้นต้องการข้อมูลที่อัปเดตจริงหรือไม่ จะทำให้คอมโพเนนต์และผู้สืบทอดทั้งหมดแสดงผลซ้ำ ซึ่งอาจส่งผลให้เกิดการแสดงผลซ้ำที่ไม่จำเป็น ซึ่งนำไปสู่การลดลงของประสิทธิภาพ โดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับบริบทที่อัปเดตบ่อยๆ หรือ tree คอมโพเนนต์ขนาดใหญ่
พิจารณาสถานการณ์ที่คุณมีบริบทธีมส่วนกลางที่ใช้สำหรับการจัดรูปแบบ หากข้อมูลเล็กน้อยที่ไม่เกี่ยวข้องภายในบริบทของธีมนั้นเปลี่ยนไป แม้แต่คอมโพเนนต์ทุกตัวที่ใช้บริบทนั้น ตั้งแต่ปุ่มไปจนถึงเลย์เอาต์ทั้งหมด ก็จะแสดงผลซ้ำ นี่เป็นเรื่องที่ไม่มีประสิทธิภาพและอาจส่งผลเสียต่อประสบการณ์ของผู้ใช้
กลยุทธ์การปรับปรุงประสิทธิภาพสำหรับ useContext
เทคนิคหลายอย่างสามารถนำมาใช้เพื่อลดผลกระทบด้านประสิทธิภาพของ useContext เราจะสำรวจกลยุทธ์เหล่านี้ โดยให้ตัวอย่างเชิงปฏิบัติและแนวทางปฏิบัติที่ดีที่สุด
1. การสร้างบริบทแบบละเอียด
แทนที่จะสร้างบริบทเดียวสำหรับแอปพลิเคชันทั้งหมดของคุณ ให้แบ่งข้อมูลของคุณออกเป็นบริบทที่เล็กลงและเฉพาะเจาะจงมากขึ้น ซึ่งจะช่วยลดขอบเขตของการแสดงผลซ้ำ เฉพาะคอมโพเนนต์ที่ขึ้นอยู่กับข้อมูลที่เปลี่ยนแปลงภายในบริบทเฉพาะเท่านั้นที่จะได้รับผลกระทบ
ตัวอย่าง:
แทนที่จะเป็น AppContext เดียวที่เก็บข้อมูลผู้ใช้ การตั้งค่าธีม และสถานะส่วนกลางอื่นๆ ให้สร้างบริบทแยกต่างหาก:
UserContext: สำหรับข้อมูลที่เกี่ยวข้องกับผู้ใช้ (สถานะการตรวจสอบสิทธิ์, โปรไฟล์ผู้ใช้ ฯลฯ)ThemeContext: สำหรับการตั้งค่าที่เกี่ยวข้องกับธีม (สี, แบบอักษร ฯลฯ)SettingsContext: สำหรับการตั้งค่าแอปพลิเคชัน (ภาษา, โซนเวลา ฯลฯ)
แนวทางนี้ช่วยให้มั่นใจได้ว่าการเปลี่ยนแปลงในบริบทหนึ่งจะไม่ทริกเกอร์การแสดงผลซ้ำในคอมโพเนนต์ที่พึ่งพาบริบทอื่นๆ ที่ไม่เกี่ยวข้อง
2. เทคนิค Memoization: React.memo และ useMemo
React.memo: ห่อคอมโพเนนต์ที่ใช้บริบทด้วย React.memo เพื่อป้องกันการแสดงผลซ้ำหาก props ไม่มีการเปลี่ยนแปลง สิ่งนี้จะดำเนินการเปรียบเทียบแบบตื้นๆ ของ props ที่ส่งไปยังคอมโพเนนต์
ตัวอย่าง:
import React, { useContext } from 'react';
const ThemeContext = React.createContext({});
function MyComponent(props) {
const theme = useContext(ThemeContext);
return <div style={{ color: theme.textColor }}>{props.children}</div>;
}
export default React.memo(MyComponent);
ในตัวอย่างนี้ MyComponent จะแสดงผลซ้ำก็ต่อเมื่อ theme.textColor เปลี่ยนแปลง อย่างไรก็ตาม React.memo จะดำเนินการเปรียบเทียบแบบตื้น ซึ่งอาจไม่เพียงพอหากค่าบริบทเป็นวัตถุที่ซับซ้อนซึ่งมีการเปลี่ยนแปลงบ่อยครั้ง ในกรณีดังกล่าว ให้พิจารณาใช้ useMemo
useMemo: ใช้ useMemo เพื่อ memoize ค่าที่ได้จากบริบท สิ่งนี้จะป้องกันการคำนวณที่ไม่จำเป็นและทำให้มั่นใจได้ว่าคอมโพเนนต์จะแสดงผลซ้ำก็ต่อเมื่อค่าเฉพาะที่ขึ้นอยู่กับการเปลี่ยนแปลง
ตัวอย่าง:
import React, { useContext, useMemo } from 'react';
const MyContext = React.createContext({});
function MyComponent() {
const contextValue = useContext(MyContext);
// Memoize the derived value
const importantValue = useMemo(() => {
return contextValue.item1 + contextValue.item2;
}, [contextValue.item1, contextValue.item2]);
return <div>{importantValue}</div>;
}
export default MyComponent;
ที่นี่ importantValue จะถูกคำนวณใหม่ก็ต่อเมื่อ contextValue.item1 หรือ contextValue.item2 เปลี่ยนแปลง หากคุณสมบัติอื่นๆ บน `contextValue` เปลี่ยนแปลง MyComponent จะไม่แสดงผลซ้ำโดยไม่จำเป็น
3. ฟังก์ชัน Selector
สร้างฟังก์ชัน selector ที่ดึงเฉพาะข้อมูลที่จำเป็นจากบริบท ซึ่งช่วยให้คอมโพเนนต์สมัครรับเฉพาะข้อมูลเฉพาะที่ต้องการ แทนที่จะเป็นวัตถุบริบททั้งหมด กลยุทธ์นี้ช่วยเสริมการสร้างบริบทแบบละเอียดและการ memoization
ตัวอย่าง:
import React, { useContext } from 'react';
const UserContext = React.createContext({});
// Selector function to extract the username
const selectUsername = (userContext) => userContext.username;
function UsernameDisplay() {
const username = selectUsername(useContext(UserContext));
return <p>Username: {username}</p>;
}
export default UsernameDisplay;
ในตัวอย่างนี้ UsernameDisplay จะแสดงผลซ้ำก็ต่อเมื่อคุณสมบัติ username ใน UserContext เปลี่ยนแปลง แนวทางนี้แยกคอมโพเนนต์ออกจากคุณสมบัติอื่นๆ ที่เก็บอยู่ใน `UserContext`
4. Custom Hooks สำหรับการใช้บริบท
ห่อหุ้มตรรกะการใช้บริบทไว้ใน custom hooks สิ่งนี้มอบวิธีที่สะอาดกว่าและนำกลับมาใช้ใหม่ได้มากขึ้นในการเข้าถึงค่าบริบทและใช้ฟังก์ชัน memoization หรือ selector นอกจากนี้ยังช่วยให้ทดสอบและบำรุงรักษาได้ง่ายขึ้น
ตัวอย่าง:
import React, { useContext, useMemo } from 'react';
const ThemeContext = React.createContext({});
// Custom hook for accessing the theme color
function useThemeColor() {
const theme = useContext(ThemeContext);
// Memoize the theme color
const themeColor = useMemo(() => theme.color, [theme.color]);
return themeColor;
}
function MyComponent() {
const themeColor = useThemeColor();
return <div style={{ color: themeColor }}>Hello, World!</div>;
}
export default MyComponent;
hook useThemeColor ห่อหุ้มตรรกะสำหรับการเข้าถึง theme.color และ memoizing ทำให้ง่ายต่อการนำตรรกะนี้กลับมาใช้ใหม่ในคอมโพเนนต์หลายตัว และช่วยให้มั่นใจได้ว่าคอมโพเนนต์จะแสดงผลซ้ำก็ต่อเมื่อ theme.color เปลี่ยนแปลง
5. ไลบรารีการจัดการสถานะ: แนวทางทางเลือก
สำหรับสถานการณ์การจัดการสถานะที่ซับซ้อน ให้พิจารณาใช้ไลบรารีการจัดการสถานะเฉพาะ เช่น Redux, Zustand หรือ Jotai ไลบรารีเหล่านี้มีคุณสมบัติขั้นสูงเพิ่มเติม เช่น การจัดการสถานะแบบรวมศูนย์ การอัปเดตสถานะที่คาดการณ์ได้ และกลไกการแสดงผลซ้ำที่ปรับให้เหมาะสม
- Redux: ไลบรารีที่ใช้งานกันอย่างแพร่หลายและเป็นผู้ใหญ่ ซึ่งมีคอนเทนเนอร์สถานะที่คาดการณ์ได้สำหรับแอป JavaScript ต้องใช้โค้ด boilerplate มากกว่า แต่มีเครื่องมือดีบักที่ยอดเยี่ยมและชุมชนขนาดใหญ่
- Zustand: โซลูชันการจัดการสถานะ bearbones ขนาดเล็ก รวดเร็ว และปรับขนาดได้ โดยใช้หลักการ flux ที่เรียบง่าย เป็นที่รู้จักในด้านความง่ายในการใช้งานและ boilerplate ขั้นต่ำ
- Jotai: การจัดการสถานะพื้นฐานและยืดหยุ่นสำหรับ React มี API ที่เรียบง่ายและใช้งานง่ายสำหรับการจัดการสถานะส่วนกลางด้วย boilerplate ขั้นต่ำ
ไลบรารีเหล่านี้อาจเป็นตัวเลือกที่ดีกว่าสำหรับการจัดการสถานะแอปพลิเคชันที่ซับซ้อน โดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับการอัปเดตบ่อยครั้งและความสัมพันธ์ของข้อมูลที่ซับซ้อน Context API ทำได้ดีในการหลีกเลี่ยงการเจาะ props แต่การจัดการสถานะเฉพาะมักจะแก้ไขปัญหาด้านประสิทธิภาพที่เกิดจากการเปลี่ยนแปลงสถานะส่วนกลาง
6. โครงสร้างข้อมูลที่ไม่เปลี่ยนรูป
เมื่อใช้วัตถุที่ซับซ้อนเป็นค่าบริบท ให้ใช้โครงสร้างข้อมูลที่ไม่เปลี่ยนรูป โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปช่วยให้มั่นใจได้ว่าการเปลี่ยนแปลงวัตถุจะสร้างอินสแตนซ์วัตถุใหม่ แทนที่จะเปลี่ยนแปลงรายการที่มีอยู่ สิ่งนี้ช่วยให้ React สามารถดำเนินการตรวจจับการเปลี่ยนแปลงที่มีประสิทธิภาพและป้องกันการแสดงผลซ้ำที่ไม่จำเป็น
ไลบรารีเช่น Immer และ Immutable.js สามารถช่วยให้คุณทำงานกับโครงสร้างข้อมูลที่ไม่เปลี่ยนรูปได้ง่ายขึ้น
ตัวอย่างโดยใช้ Immer:
import React, { createContext, useState, useContext, useCallback } from 'react';
import { useImmer } from 'use-immer';
const MyContext = createContext();
function MyProvider({ children }) {
const [state, updateState] = useImmer({
item1: 'value1',
item2: 'value2',
});
const updateItem1 = useCallback((newValue) => {
updateState((draft) => {
draft.item1 = newValue;
});
}, [updateState]);
return (
<MyContext.Provider value={{ state, updateItem1 }}>
{children}
</MyContext.Provider>
);
}
function MyComponent() {
const { state, updateItem1 } = useContext(MyContext);
return (
<div>
<p>Item 1: {state.item1}</p>
<button onClick={() => updateItem1('new value')}>Update Item 1</button>
</div>
);
}
export { MyContext, MyProvider, MyComponent };
ในตัวอย่างนี้ useImmer ช่วยให้มั่นใจได้ว่าการอัปเดตสถานะจะสร้างอ็อบเจกต์สถานะใหม่ โดยทริกเกอร์การแสดงผลซ้ำเมื่อจำเป็นเท่านั้น
7. การรวบรวมการอัปเดตสถานะ
React จะรวบรวมการอัปเดตสถานะหลายรายการลงในรอบการแสดงผลซ้ำเพียงครั้งเดียวโดยอัตโนมัติ อย่างไรก็ตาม ในบางสถานการณ์ คุณอาจต้องรวบรวมการอัปเดตด้วยตนเอง สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อต้องรับมือกับการดำเนินการแบบอะซิงโครนัสหรือการอัปเดตหลายรายการในช่วงเวลาสั้นๆ
คุณสามารถใช้ ReactDOM.unstable_batchedUpdates (มีอยู่ใน React 18 และก่อนหน้านี้ และโดยทั่วไปไม่จำเป็นด้วยการรวบรวมอัตโนมัติใน React 18+) เพื่อรวบรวมการอัปเดตด้วยตนเอง
8. หลีกเลี่ยงการอัปเดตบริบทที่ไม่จำเป็น
ตรวจสอบให้แน่ใจว่าคุณอัปเดตค่าบริบทก็ต่อเมื่อมีการเปลี่ยนแปลงข้อมูลจริงเท่านั้น หลีกเลี่ยงการอัปเดตบริบทด้วยค่าเดียวกันโดยไม่จำเป็น เนื่องจากสิ่งนี้จะยังคงทริกเกอร์การแสดงผลซ้ำ
ก่อนที่จะอัปเดตบริบท ให้เปรียบเทียบค่าใหม่กับค่าก่อนหน้าเพื่อให้แน่ใจว่ามีความแตกต่าง
ตัวอย่างในโลกแห่งความเป็นจริงในประเทศต่างๆ
ลองพิจารณาว่าเทคนิคการปรับปรุงประสิทธิภาพเหล่านี้สามารถนำไปใช้ในสถานการณ์ต่างๆ ทั่วประเทศต่างๆ ได้อย่างไร:
- แพลตฟอร์มอีคอมเมิร์ซ (ทั่วโลก): แพลตฟอร์มอีคอมเมิร์ซใช้
CartContextเพื่อจัดการตะกร้าสินค้าของผู้ใช้ หากไม่มีการปรับปรุงประสิทธิภาพ คอมโพเนนต์ทุกตัวบนหน้าอาจแสดงผลซ้ำเมื่อมีการเพิ่มสินค้าลงในตะกร้า โดยใช้ฟังก์ชัน selector และReact.memoเฉพาะสรุปตะกร้าสินค้าและคอมโพเนนต์ที่เกี่ยวข้องเท่านั้นที่แสดงผลซ้ำ การใช้ไลบรารีอย่าง Zustand สามารถจัดการตะกร้าสินค้าได้อย่างมีประสิทธิภาพ นี่สามารถใช้ได้ทั่วโลก โดยไม่คำนึงถึงภูมิภาค - แดชบอร์ดทางการเงิน (สหรัฐอเมริกา, สหราชอาณาจักร, เยอรมนี): แดชบอร์ดทางการเงินแสดงราคาหุ้นและข้อมูลพอร์ตการลงทุนแบบเรียลไทม์
StockDataContextให้ข้อมูลหุ้นล่าสุด เพื่อป้องกันการแสดงผลซ้ำมากเกินไปuseMemoจะใช้เพื่อ memoize ค่าที่ได้ เช่น มูลค่าพอร์ตการลงทุนรวม การปรับปรุงประสิทธิภาพเพิ่มเติมอาจเกี่ยวข้องกับการใช้ฟังก์ชัน selector เพื่อดึงข้อมูลเฉพาะสำหรับแต่ละแผนภูมิ ไลบรารีเช่น Recoil อาจเป็นประโยชน์ - แอปพลิเคชันโซเชียลมีเดีย (อินเดีย, บราซิล, อินโดนีเซีย): แอปพลิเคชันโซเชียลมีเดียใช้
UserContextเพื่อจัดการการตรวจสอบสิทธิ์ของผู้ใช้และข้อมูลโปรไฟล์ ใช้การสร้างบริบทแบบละเอียดเพื่อแยกบริบทโปรไฟล์ผู้ใช้ออกจากบริบทการตรวจสอบสิทธิ์ โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปใช้เพื่อให้แน่ใจว่าการตรวจจับการเปลี่ยนแปลงมีประสิทธิภาพ ไลบรารีเช่น Immer สามารถลดความซับซ้อนของการอัปเดตสถานะ - เว็บไซต์จองการเดินทาง (ญี่ปุ่น, เกาหลีใต้, จีน): เว็บไซต์จองการเดินทางใช้
SearchContextเพื่อจัดการเกณฑ์การค้นหาและผลลัพธ์ Custom hooks ใช้เพื่อห่อหุ้มตรรกะสำหรับการเข้าถึงและ memoizing ผลลัพธ์การค้นหา รวบรวมการอัปเดตสถานะเพื่อปรับปรุงประสิทธิภาพเมื่อใช้ตัวกรองหลายตัวพร้อมกัน
ข้อมูลเชิงลึกที่นำไปปฏิบัติได้และแนวทางปฏิบัติที่ดีที่สุด
- สร้างโปรไฟล์แอปพลิเคชันของคุณ: ใช้ React DevTools เพื่อระบุคอมโพเนนต์ที่แสดงผลซ้ำบ่อยๆ
- เริ่มต้นด้วยบริบทแบบละเอียด: แบ่งสถานะส่วนกลางของคุณออกเป็นบริบทที่เล็กลงและจัดการได้ง่ายขึ้น
- ใช้ memoization อย่างมีกลยุทธ์: ใช้
React.memoและuseMemoเพื่อป้องกันการแสดงผลซ้ำที่ไม่จำเป็น - ใช้ฟังก์ชัน selector: ดึงเฉพาะข้อมูลที่จำเป็นจากบริบท
- พิจารณาไลบรารีการจัดการสถานะ: สำหรับการจัดการสถานะที่ซับซ้อน ให้สำรวจไลบรารีเช่น Redux, Zustand หรือ Jotai
- นำโครงสร้างข้อมูลที่ไม่เปลี่ยนรูปมาใช้: ใช้ไลบรารีเช่น Immer เพื่อลดความซับซ้อนในการทำงานกับข้อมูลที่ไม่เปลี่ยนรูป
- ตรวจสอบและปรับปรุงประสิทธิภาพ: ตรวจสอบประสิทธิภาพของแอปพลิเคชันของคุณอย่างต่อเนื่องและปรับปรุงการใช้งานบริบทตามความจำเป็น
บทสรุป
Context API ของ React เมื่อใช้งานอย่างรอบคอบและปรับให้เหมาะสมด้วยเทคนิคที่กล่าวมา จะนำเสนอวิธีที่ทรงพลังและสะดวกในการแชร์ข้อมูลทั่วทั้ง tree คอมโพเนนต์ของคุณ ด้วยการทำความเข้าใจถึงข้อผิดพลาดด้านประสิทธิภาพที่อาจเกิดขึ้นและใช้กลยุทธ์การปรับปรุงประสิทธิภาพที่เหมาะสม คุณสามารถมั่นใจได้ว่าแอปพลิเคชัน React ของคุณยังคงมีประสิทธิภาพ ปรับขนาดได้ และดูแลรักษาได้ โดยไม่คำนึงถึงขนาดหรือความซับซ้อน
อย่าลืมสร้างโปรไฟล์แอปพลิเคชันของคุณเสมอและระบุพื้นที่ที่ต้องปรับปรุงประสิทธิภาพ เลือกกลยุทธ์ที่เหมาะสมที่สุดกับความต้องการและบริบทเฉพาะของคุณ ด้วยการปฏิบัติตามแนวทางเหล่านี้ คุณสามารถใช้ประโยชน์จากพลังของ useContext ได้อย่างมีประสิทธิภาพ และสร้างแอปพลิเคชัน React ที่มีประสิทธิภาพสูงซึ่งมอบประสบการณ์การใช้งานที่ยอดเยี่ยม