reactjs - React: Çocukların yeniden render edilmesi için büyük ağaç yapısını önlemek


Yaklaşık 14 bin düğüme sahip ağaç/klasör yapısında verim var. Tüm ağacın alt öğelerinin yeniden render edilmesini önlemek istiyorum çünkü bu biraz uzun sürüyor. Bir düğüm, bir butona tıklanarak genişletilebilir veya küçültülebilir ve bu, düğümün id'sinin Redux durumunda saklanan bir expanded Set'ine eklenmesini sağlar. Şu anda, Set'e bir kategori eklediğimde tüm ağaç yeniden render ediliyor. Bunu nasıl önleyebilirim?

Veri yapısı:

[
  {
    "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
]


Çocuklarını özyinelemeli olarak render eden özyinelemeli bir TreeTableBranch bileşenim var:

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}
        />
     )}
  )
}

Ancak, expanded listesi değiştirildiği için tüm alt öğeler yeniden render edilir. Aşağıdaki şekilde useMemo() kullanmayı denedim:

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]);

Ancak bu işe yaramaz, muhtemelen expanded listesinin değiştirilmiş olmasından dolayı.

Bunu şu şekilde React.memo() kullanmayı da denedim:

const areEqual = (prevProps: Props, nextProps: Props) => {
  return prevProps.shouldExpand === nextProps.shouldExpand;
};

Ama bu, diğer çocukların yeniden render edilmesini engellemiyor.

Her türlü yardım veya ipucu takdir edilir!

Cevap #1

Ağacın yapısını değiştirmeden yeniden render etmeyi önleyemedim. Ağacı bir listeye düzleştirdim ve TreeTableBranch'in React.memo kullandığından emin oldum, @Sam’ın belirttiği gibi, karşılaştırma fonksiyonu eklemeden şu şekilde: export default React.memo(TreeTableBranch); ve aynı şekilde onun ebeveyni de. Ayrıca @glinda93’ün önerdiği gibi onExpand, onAddCategory ve onDeleteCategory fonksiyon propslarını geçmeyi de kaldırdım, fakat bunun sorunu çözüp çözmediğinden %100 emin değilim.

Sonunda, büyük ağacın ilk renderinin hâlâ çok uzun sürdüğünü fark ettim, bu yüzden bu düzleştirilmiş yapı ile listeyi sanallaştırmak için react-window kullanmak çok daha kolay oldu.