From 18aaf86a421b2a761f120fb9d12b34ea65dc8360 Mon Sep 17 00:00:00 2001
From: lokmeinmatz <matze.kind@web.de>
Date: Sun, 13 Jun 2021 20:21:51 +0200
Subject: [PATCH] fixed render performance for SportartenTable

---
 package.json                                  |   1 +
 .../admin/sports/SportartenTable.tsx          | 194 ++++++++++++------
 2 files changed, 131 insertions(+), 64 deletions(-)

diff --git a/package.json b/package.json
index 8999f01..cd1fc76 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
         "@types/react-dom": "^16.9.0",
         "@types/react-redux": "^7.1.7",
         "babel-jest": "^26.6.0",
+        "fast-deep-equal": "^3.1.3",
         "history": "^5.0.0",
         "react": "^17.0.2",
         "react-dnd": "^14.0.2",
diff --git a/src/components/admin/sports/SportartenTable.tsx b/src/components/admin/sports/SportartenTable.tsx
index c559c96..c8b999a 100644
--- a/src/components/admin/sports/SportartenTable.tsx
+++ b/src/components/admin/sports/SportartenTable.tsx
@@ -11,26 +11,132 @@ import {
 import AddIcon from '@material-ui/icons/Add'
 import { ArrowDownward, ArrowUpward } from '@material-ui/icons'
 import ClearIcon from '@material-ui/icons/Clear'
-import {ICategorie, ISport} from "./sportsMockData";
+import { ICategorie, ISport } from './sportsMockData'
+import deepEqual from 'fast-deep-equal'
 
 interface SportartenTableProps {
     categories: ICategorie[]
     sportarten: ISport[]
-    activ: boolean,
-    handlerSport:any,
-    handlerCategorie:any,
+    activ: boolean
+    handlerSport: any
+    handlerCategorie: any
 }
 
+interface MemoRowProps {
+    sport: ISport
+    listIdx: number
+    categoryWeightChange: (category: string, weight: number) => void
+    onToggleActive: () => void
+    onDelete: () => void
+}
+
+function compareRowProps(old: MemoRowProps, n: MemoRowProps): boolean {
+    console.log(old.sport, n.sport)
+
+    const sportUnchanged = deepEqual(old.sport, n.sport)
+    //const callbacksUnchanged = old.categoryWeightChange == n.categoryWeightChange && old.onDelete == n.onDelete && old.onToggleActive == n.onToggleActive
+
+    //console.log('sportUnchanged: ', sportUnchanged, 'callbacksUnchanged: ', callbacksUnchanged);
+    console.log(sportUnchanged && old.listIdx === n.listIdx)
+
+    return sportUnchanged && old.listIdx === n.listIdx
+}
+
+const MemoRow = React.memo(
+    ({
+        sport,
+        categoryWeightChange,
+        onToggleActive,
+        onDelete
+    }: MemoRowProps) => {
+        return (
+            <TableRow>
+                <TableCell> {sport.name}</TableCell>
+                {Object.keys(sport.categoryWeights).map(function (key, idx) {
+                    // TODO: use diffrent key?
+                    return (
+                        <TableCell key={key}>
+                            <TextField
+                                id="outlined-basic"
+                                type="number"
+                                variant="outlined"
+                                value={sport.categoryWeights[key]}
+                                onChange={(e) => {
+                                    categoryWeightChange(
+                                        key,
+                                        parseInt(e.currentTarget.value, 10)
+                                    )
+                                }}
+                            />
+                        </TableCell>
+                    )
+                })}
+                <TableCell />
+                <TableCell>
+                    <a href={sport.url} target="_blank">
+                        {sport.url}
+                    </a>
+                </TableCell>
+                <TableCell>
+                    <IconButton>
+                        {sport.active ? (
+                            <ArrowDownward
+                                onClick={() => {
+                                    onToggleActive()
+                                }}
+                            />
+                        ) : (
+                            <ArrowUpward
+                                onClick={() => {
+                                    onToggleActive()
+                                }}
+                            />
+                        )}
+                    </IconButton>
+                </TableCell>
+                <TableCell>
+                    <IconButton>
+                        <ClearIcon
+                            onClick={() => {
+                                onDelete()
+                            }}
+                        />
+                    </IconButton>
+                </TableCell>
+            </TableRow>
+        )
+    },
+    compareRowProps
+)
+
 export const SportartenTable: React.FC<SportartenTableProps> = ({
     sportarten,
     categories,
     activ,
     handlerSport,
-    handlerCategorie,
-
+    handlerCategorie
+}: SportartenTableProps) => {
+    const deleteEntry = (idx: number) => {
+        let copy = [...sportarten]
+        copy.splice(idx, 1)
+        handlerSport(copy)
+    }
 
+    const toggleActive = (idx: number) => {
+        let copy = [...sportarten]
+        copy[idx].active = !copy[idx].active
+        handlerSport(copy)
+    }
 
-}: SportartenTableProps) => {
+    const changeWeight = (idx: number, category: string, weight: number) => {
+        let copy = [...sportarten]
+        copy[idx] = { ...copy[idx] }
+        copy[idx].categoryWeights = {
+            ...copy[idx].categoryWeights,
+            [category]: weight
+        }
+        handlerSport(copy)
+    }
 
     return (
         <Table>
@@ -38,7 +144,11 @@ export const SportartenTable: React.FC<SportartenTableProps> = ({
                 <TableRow>
                     <TableCell> Sportarten </TableCell>
                     {categories.map((elem) => {
-                        return <TableCell key={elem.categorieId}>{elem.categorie}</TableCell>
+                        return (
+                            <TableCell key={elem.categorieId}>
+                                {elem.categorie}
+                            </TableCell>
+                        )
                     })}
                     <TableCell>
                         <IconButton>
@@ -51,63 +161,19 @@ export const SportartenTable: React.FC<SportartenTableProps> = ({
                 </TableRow>
             </TableHead>
             <TableBody>
-                {sportarten.map((elem,itx) => {
-                    if (elem.active!=activ) return
+                {sportarten.map((elem, itx) => {
+                    if (elem.active !== activ) return null
                     return (
-                        <TableRow key={elem.name}>
-                            <TableCell> {elem.name}</TableCell>
-                            {Object.keys(elem.categoryWeights).map(function(key, idx) {
-                                // TODO: use diffrent key?
-                                return (
-                                    <TableCell key={key}>
-                                        <TextField
-                                            id="outlined-basic"
-                                            type="number"
-                                            variant="outlined"
-                                            value={elem.categoryWeights[key]}
-                                            onChange={(e)=>{
-                                                    let copy = [...sportarten]
-                                                    copy[itx].categoryWeights[key]=parseInt(e.currentTarget.value,10)
-                                                    handlerSport(copy)
-                                                }
-                                            }
-                                        />
-                                    </TableCell>
-                                )
-                            })}
-                            <TableCell />
-                            <TableCell>
-                                <a href={elem.url} target="_blank">
-                                    {elem.url}
-                                </a>
-                            </TableCell>
-                            <TableCell>
-                                <IconButton>
-                                    {activ ? (
-                                        <ArrowDownward onClick={()=>{
-                                            let copy = [...sportarten]
-                                            copy[itx].active=false
-                                            handlerSport(copy)
-                                        }}/>
-                                    ) : (
-                                        <ArrowUpward onClick={()=>{
-                                            let copy = [...sportarten]
-                                            copy[itx].active=true
-                                            handlerSport(copy)
-                                        }}/>
-                                    )}
-                                </IconButton>
-                            </TableCell>
-                            <TableCell>
-                                <IconButton>
-                                    <ClearIcon onClick={()=>{
-                                        let copy = [...sportarten]
-                                        copy.splice(itx,1)
-                                        handlerSport(copy)
-                                    }}/>
-                                </IconButton>
-                            </TableCell>
-                        </TableRow>
+                        <MemoRow
+                            key={elem.name}
+                            sport={elem}
+                            listIdx={itx}
+                            onDelete={() => deleteEntry(itx)}
+                            onToggleActive={() => toggleActive(itx)}
+                            categoryWeightChange={(cat, weight) =>
+                                changeWeight(itx, cat, weight)
+                            }
+                        />
                     )
                 })}
             </TableBody>
-- 
GitLab