提高React Kendo DataGrid的渲染性能

发布于 2025-01-13 13:34:12 字数 3782 浏览 0 评论 0原文

我有一个反应剑道数据网格,它的单元格是可选的。有 385 行,每行有 4 个可选单元格。

问题是;当选中任何复选框时,整个网格都会重新渲染。因此,检查大约需要3秒。是否可以仅重新生成编辑过的单元格?

import { useDispatch } from "react-redux";
import { setScopes } from "../../redux/actions/scopeActions";

import {
  Grid,
  GridColumn as Column,
  GridToolbar,
} from "@progress/kendo-react-grid";
import { filterBy } from "@progress/kendo-data-query";
import "@progress/kendo-theme-material/dist/all.css";
import { Checkbox } from "@material-ui/core";

function NewApiScopesTable({ scopes }) {
  const dispatch = useDispatch();
  const [rows, setRows] = useState(scopes);

  //   const [filter, setFilter] = useState();
  //   const filterChange = (event) => {
  //     setData(filterBy(scopes, event.filter));
  //     setFilter(event.filter);
  //   };

  useEffect(() => {
    setRows(scopes);
  }, [scopes]);

  useEffect(() => {
    const selectedRows = rows.filter(
      (row) => !!row.get || !!row.post || !!row.put || !!row.delete
    );
    dispatch(setScopes(selectedRows));
  }, [rows]);

  const handleSelect = (row) => {
    const newRows = [...rows];
    const index = newRows.findIndex((r) => r.id === row.id);
    newRows[index] = { ...row };
    setRows(newRows);
  };

  const getCell = (props) => {
    return (
      <td>
        <Checkbox
          inputProps={{ "aria-label": "primary checkbox" }}
          checked={props.dataItem.get}
          onChange={() =>
            handleSelect({ ...props.dataItem, get: !props.dataItem.get })
          }
        />
      </td>
    );
  };

  const postCell = (props) => {
    if (!props.dataItem.isPostEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.post}
            onChange={() =>
              handleSelect({ ...props.dataItem, post: !props.dataItem.post })
            }
          />
        </td>
      );
    }
  };
  const putCell = (props) => {
    if (!props.dataItem.isPutEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.put}
            onChange={() =>
              handleSelect({ ...props.dataItem, put: !props.dataItem.put })
            }
          />
        </td>
      );
    }
  };
  const deleteCell = (props) => {
    if (!props.dataItem.isDeleteEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.delete}
            onChange={() =>
              handleSelect({
                ...props.dataItem,
                delete: !props.dataItem.delete,
              })
            }
          />
        </td>
      );
    }
  };


  console.log("run");
  return (
    <Grid
      style={{
        height: "500px",
      }}
      data={rows}
      //   filter={filter}
      //   onFilterChange={filterChange}
    >
      <GridToolbar>
        <input type="search" id="site-search" name="q" onChange />
      </GridToolbar>
      <Column field="name" title="Endpoint Name" width="400px" />
      <Column field="get" title="GET" cell={getCell} />
      <Column field="post" title="POST" cell={postCell} />
      <Column field="put" title="PUT" cell={putCell} />
      <Column field="delete" title="DELETE" cell={deleteCell} />
    </Grid>
  );
}

export const MemoizedNewApiScopesTable = React.memo(NewApiScopesTable);

I have a react-kendo datagrid and its cells are selectable. There are 385 rows and each row has 4 Selectable cells.

The problem is; When any of the checkboxes is checked, the whole grid is rerender. Accordingly, it takes about 3 seconds to be checked. Is it possible to regenerate only the edited cell?

import { useDispatch } from "react-redux";
import { setScopes } from "../../redux/actions/scopeActions";

import {
  Grid,
  GridColumn as Column,
  GridToolbar,
} from "@progress/kendo-react-grid";
import { filterBy } from "@progress/kendo-data-query";
import "@progress/kendo-theme-material/dist/all.css";
import { Checkbox } from "@material-ui/core";

function NewApiScopesTable({ scopes }) {
  const dispatch = useDispatch();
  const [rows, setRows] = useState(scopes);

  //   const [filter, setFilter] = useState();
  //   const filterChange = (event) => {
  //     setData(filterBy(scopes, event.filter));
  //     setFilter(event.filter);
  //   };

  useEffect(() => {
    setRows(scopes);
  }, [scopes]);

  useEffect(() => {
    const selectedRows = rows.filter(
      (row) => !!row.get || !!row.post || !!row.put || !!row.delete
    );
    dispatch(setScopes(selectedRows));
  }, [rows]);

  const handleSelect = (row) => {
    const newRows = [...rows];
    const index = newRows.findIndex((r) => r.id === row.id);
    newRows[index] = { ...row };
    setRows(newRows);
  };

  const getCell = (props) => {
    return (
      <td>
        <Checkbox
          inputProps={{ "aria-label": "primary checkbox" }}
          checked={props.dataItem.get}
          onChange={() =>
            handleSelect({ ...props.dataItem, get: !props.dataItem.get })
          }
        />
      </td>
    );
  };

  const postCell = (props) => {
    if (!props.dataItem.isPostEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.post}
            onChange={() =>
              handleSelect({ ...props.dataItem, post: !props.dataItem.post })
            }
          />
        </td>
      );
    }
  };
  const putCell = (props) => {
    if (!props.dataItem.isPutEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.put}
            onChange={() =>
              handleSelect({ ...props.dataItem, put: !props.dataItem.put })
            }
          />
        </td>
      );
    }
  };
  const deleteCell = (props) => {
    if (!props.dataItem.isDeleteEnable) {
      return <td></td>;
    } else {
      return (
        <td>
          <Checkbox
            inputProps={{ "aria-label": "primary checkbox" }}
            checked={props.dataItem.delete}
            onChange={() =>
              handleSelect({
                ...props.dataItem,
                delete: !props.dataItem.delete,
              })
            }
          />
        </td>
      );
    }
  };


  console.log("run");
  return (
    <Grid
      style={{
        height: "500px",
      }}
      data={rows}
      //   filter={filter}
      //   onFilterChange={filterChange}
    >
      <GridToolbar>
        <input type="search" id="site-search" name="q" onChange />
      </GridToolbar>
      <Column field="name" title="Endpoint Name" width="400px" />
      <Column field="get" title="GET" cell={getCell} />
      <Column field="post" title="POST" cell={postCell} />
      <Column field="put" title="PUT" cell={putCell} />
      <Column field="delete" title="DELETE" cell={deleteCell} />
    </Grid>
  );
}

export const MemoizedNewApiScopesTable = React.memo(NewApiScopesTable);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人疚 2025-01-20 13:34:12

老问题,但对于后来偶然发现这个问题的人来说,对我有用的是记住任何自定义单元格。 (不确定这是否会解决您的特定性能问题,但现在应该会有所帮助)

  const handleSelect = useCallback((row) => {
    const newRows = [...rows];
    const index = newRows.findIndex((r) => r.id === row.id);
    newRows[index] = { ...row };
    setRows(newRows);
  }, [//dependencies here]);

  const getCell = useMemo((props) => {
    return (
      <td>
        <Checkbox
          inputProps={{ "aria-label": "primary checkbox" }}
          checked={props.dataItem.get}
          onChange={() =>
            handleSelect({ ...props.dataItem, get: !props.dataItem.get })
          }
        />
      </td>
    );
  },[handleSelect, props.dataItem]);

请注意添加的 useMemo 和 useCallback 挂钩。 (应用任何依赖项以使 linter 满意,我只添加了一些)

您放入 useMemo 的依赖项数组中的任何函数都需要 useCallback,否则它将运行每个渲染。

对所有自定义单元格遵循此模式,看看它是否有助于性能。

Old question but for anyone stumbling upon this later, what worked for me was to memoize any custom cells. (not sure if this will fix your particular performance issue or now but it should help)

  const handleSelect = useCallback((row) => {
    const newRows = [...rows];
    const index = newRows.findIndex((r) => r.id === row.id);
    newRows[index] = { ...row };
    setRows(newRows);
  }, [//dependencies here]);

  const getCell = useMemo((props) => {
    return (
      <td>
        <Checkbox
          inputProps={{ "aria-label": "primary checkbox" }}
          checked={props.dataItem.get}
          onChange={() =>
            handleSelect({ ...props.dataItem, get: !props.dataItem.get })
          }
        />
      </td>
    );
  },[handleSelect, props.dataItem]);

Notice the useMemo and useCallback hooks added. (apply any dependencies to make the linter happy, I only added a few)

The useCallback is needed on any function you put in the dependency array of useMemo, otherwise it will run every render.

Follow this patter for all custom cells and see if it helps performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文