reactjs - React: ป้องกันโครงสร้างต้นไม้ขนาดใหญ่ในการเรนเดอร์ส่วนลูกใหม่
ฉันมีข้อมูลที่มีโครงสร้างเป็นต้นไม้/ไดเร็กทอรี โดยมีโหนดประมาณ 14,000 โหนด ฉันต้องการป้องกันไม่ให้โหนดลูกทั้งหมดของต้นไม้ทำการแสดงผลใหม่ เพราะมันใช้เวลานานมาก โหนดสามารถขยายหรือย่อได้เมื่อคลิกปุ่ม ซึ่งจะเพิ่มไอดีของโหนดนั้นลงใน expanded Set ที่บันทึกอยู่ใน Redux state ปัจจุบัน เมื่อเพิ่มหมวดหมู่ลงใน Set ทั้งต้นไม้จะถูกเรนเดอร์ใหม่ ฉันจะป้องกันสิ่งนี้ได้อย่างไร?
โครงสร้างข้อมูล:
[
{
"id": "1",
"name": "Category 1",
"children": [
{
"id": "11",
"name": "Category 1-1",
"children": []
}
]
},
{
"id": "2",
"name": "Category 2",
"children": [
{
"id": "3",
"name": "Category 2-1",
"children": [
...children
]
}
]
}
... and so forth
]
ฉันมีคอมโพเนนต์ TreeTableBranch แบบวนซ้ำ ซึ่งทำการเรนเดอร์ลูกของมันแบบวนซ้ำ:
const TreeTableBranch: React.FC<Props> = ({
node,
level,
onExpand
}) => {
const expanded = useSelector((state: AppState) => state.categories.expanded);
const shouldExpand = expanded.has(node.category.id);
return (
...lots of divs for rendering a node
<button onClick={onExpand}>Expand<Button/>
{ shouldExpand &&
node.children.map((v,i) => (
<TreeTableBranch
key={v.category.id}
node={v}
level={level + 1}
onExpand={onExpand}
/>
)}
)
}
อย่างไรก็ตาม เนื่องจากรายการ expanded ถูกแก้ไข เด็กทุกตัวจึงถูกเรนเดอร์ใหม่ ฉันได้ลองใช้ useMemo() ดังนี้:
const children = useMemo(() => {
return (
shouldExpand &&
node.children.map((v, i) => (
<TreeTableBranch
key={`category-branch-${v.category.id}`}
node={v}
level={level + 1}
onExpand={onExpand}
onAddCategory={onAddCategory}
onDeleteCategory={onDeleteCategory}
/>
))
);
}, [shouldExpand]);
อย่างไรก็ตาม นี่ไม่ทำงาน อาจเป็นเพราะรายการ expanded ถูกแก้ไข
ฉันยังได้ลองใช้ React.memo() แบบนี้ด้วย:
const areEqual = (prevProps: Props, nextProps: Props) => {
return prevProps.shouldExpand === nextProps.shouldExpand;
};
แต่สิ่งนี้ไม่ได้หยุดเด็กคนอื่นจากการเรนเดอร์ใหม่
ขอขอบคุณสำหรับความช่วยเหลือหรือคำแนะนำทุกอย่าง!
คำตอบ #1
ฉันไม่สามารถป้องกันการเรนเดอร์ซ้ำได้โดยไม่เปลี่ยนโครงสร้างของต้นไม้ ฉันจึงทำให้ต้นไม้แบนราบเป็นรายการและทำให้แน่ใจว่า TreeTableBranch ใช้ React.memo ดังนี้: export default React.memo(TreeTableBranch); ตามที่ @Sam กล่าวโดยไม่เพิ่มฟังก์ชันการเปรียบเทียบ รวมถึงพาเรนต์ของมันด้วย ฉันยังเอาการส่งผ่าน props ของฟังก์ชัน onExpand, onAddCategory และ onDeleteCategory ออกตามที่ @glinda93 แนะนำ แม้ว่าฉันจะไม่แน่ใจ 100% ว่าสิ่งนี้แก้ปัญหาได้หรือไม่
สุดท้าย ฉันก็เข้าใจว่าการเรนเดอร์ต้นไม้ใหญ่ครั้งแรกยังใช้เวลานานเกินไป ดังนั้นด้วยโครงสร้างแบบแบนนี้ การใช้ react-window เพื่อทำให้รายการเสมือนจริงจึงง่ายขึ้นมาก