ค้นหาเว็บไซต์

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 เพื่อทำให้รายการเสมือนจริงจึงง่ายขึ้นมาก