reactjs - 处理ag网格 react 并渲染复选框网格

标签 reactjs ag-grid apollo react-apollo ag-grid-react

我正在搞乱 ag-grid、react-apollo,一切似乎都工作正常。这里的目标是单击复选框并发生突变/网络请求来修改某些数据。我遇到的问题是,它会重新绘制整行,这可能非常慢,但我实际上只是尝试更新单元格本身,以便它快速且用户体验更好。我的一个想法是进行乐观更新并更新我的缓存/利用我的缓存。你们采取了哪些方法。

列和行数据都是通过 apollo 查询获取的。

这是一些代码:

复选框渲染器

import React, { Component } from "react";
import Checkbox from "@material-ui/core/Checkbox";
import _ from "lodash";

class CheckboxItem extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: false
    };
    this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
  }

  componentDidMount() {
    this.setDefaultState();
  }

  setDefaultState() {
    const { data, colDef, api } = this.props;
    const { externalData } = api;
    if (externalData && externalData.length > 0) {
      if (_.find(data.roles, _.matchesProperty("name", colDef.headerName))) {
        this.setState({
          value: true
        });
      }
    }
  }

  updateGridAssociation(checked) {
    const { data, colDef } = this.props;
    // const { externalData, entitySpec, fieldSpec } = this.props.api;
    // console.log(data);
    // console.log(colDef);
    if (checked) {
      this.props.api.assign(data.id, colDef.id);
      return;
    }
    this.props.api.unassign(data.id, colDef.id);
    return;
  }

  handleCheckboxChange(event) {
    const checked = !this.state.value;
    this.updateGridAssociation(checked);
    this.setState({ value: checked });
  }

  render() {
    return (
      <Checkbox
        checked={this.state.value}
        onChange={this.handleCheckboxChange}
      />
    );
  }
}

export default CheckboxItem;

网格本身:

import React, { Component } from "react";
import { graphql, compose } from "react-apollo";
import gql from "graphql-tag";
import Grid from "@material-ui/core/Grid";
import _ from "lodash";
import { AgGridReact } from "ag-grid-react";
import { CheckboxItem } from "../Grid";
import "ag-grid/dist/styles/ag-grid.css";
import "ag-grid/dist/styles/ag-theme-material.css";

class UserRole extends Component {
  constructor(props) {
    super(props);
    this.api = null;
  }

  generateColumns = roles => {
    const columns = [];
    const initialColumn = {
      headerName: "User Email",
      editable: false,
      field: "email"
    };
    columns.push(initialColumn);
    _.forEach(roles, role => {
      const roleColumn = {
        headerName: role.name,
        editable: false,
        cellRendererFramework: CheckboxItem,
        id: role.id,
        suppressMenu: true,
        suppressSorting: true
      };
      columns.push(roleColumn);
    });
    if (this.api.setColumnDefs && roles) {
      this.api.setColumnDefs(columns);
    }
    return columns;
  };

  onGridReady = params => {
    this.api = params.api;
    this.columnApi = params.columnApi;
    this.api.assign = (userId, roleId) => {
      this.props.assignRole({
        variables: { userId, roleId },
        refetchQueries: () => ["allUserRoles", "isAuthenticated"]
      });
    };

    this.api.unassign = (userId, roleId) => {
      this.props.unassignRole({
        variables: { userId, roleId },
        refetchQueries: () => ["allUserRoles", "isAuthenticated"]
      });
    };
    params.api.sizeColumnsToFit();
  };

  onGridSizeChanged = params => {
    const gridWidth = document.getElementById("grid-wrapper").offsetWidth;
    const columnsToShow = [];
    const columnsToHide = [];
    let totalColsWidth = 0;
    const allColumns = params.columnApi.getAllColumns();
    for (let i = 0; i < allColumns.length; i++) {
      const column = allColumns[i];
      totalColsWidth += column.getMinWidth();
      if (totalColsWidth > gridWidth) {
        columnsToHide.push(column.colId);
      } else {
        columnsToShow.push(column.colId);
      }
    }
    params.columnApi.setColumnsVisible(columnsToShow, true);
    params.columnApi.setColumnsVisible(columnsToHide, false);
    params.api.sizeColumnsToFit();
  };

  onCellValueChanged = params => {};

  render() {
    console.log(this.props);
    const { users, roles } = this.props.userRoles;
    if (this.api) {
      this.api.setColumnDefs(this.generateColumns(roles));
      this.api.sizeColumnsToFit();
      this.api.externalData = roles;
      this.api.setRowData(_.cloneDeep(users));
    }
    return (
      <Grid
        item
        xs={12}
        sm={12}
        className="ag-theme-material"
        style={{
          height: "80vh",
          width: "100vh"
        }}
      >
        <AgGridReact
          onGridReady={this.onGridReady}
          onGridSizeChanged={this.onGridSizeChanged}
          columnDefs={[]}
          enableSorting
          pagination
          paginationAutoPageSize
          enableFilter
          enableCellChangeFlash
          rowData={_.cloneDeep(users)}
          deltaRowDataMode={true}
          getRowNodeId={data => data.id}
          onCellValueChanged={this.onCellValueChanged}
        />
      </Grid>
    );
  }
}

const userRolesQuery = gql`
  query allUserRoles {
    users {
      id
      email
      roles {
        id
        name
      }
    }

    roles {
      id
      name
    }
  }
`;

const unassignRole = gql`
  mutation($userId: String!, $roleId: String!) {
    unassignUserRole(userId: $userId, roleId: $roleId) {
      id
      email
      roles {
        id
        name
      }
    }
  }
`;

const assignRole = gql`
  mutation($userId: String!, $roleId: String!) {
    assignUserRole(userId: $userId, roleId: $roleId) {
      id
      email
      roles {
        id
        name
      }
    }
  }
`;

export default compose(
  graphql(userRolesQuery, {
    name: "userRoles",
    options: { fetchPolicy: "cache-and-network" }
  }),
  graphql(unassignRole, {
    name: "unassignRole"
  }),
  graphql(assignRole, {
    name: "assignRole"
  })
)(UserRole);

enter image description here

最佳答案

我不知道 ag-grid,但是......在这种情况下发出请求会导致整个网格(UserRole 组件)重绘

当您传递影响整个父状态的操作(给子级)时,这是正常的(新数据到达 props => 重绘)。

您可以通过 shouldComponentUpdate() 来避免这种情况 - 例如仅当行数发生变化时才重绘。

但是还有另一个问题 - 您正在进行乐观的更改(更改复选框状态) - 如果突变失败怎么办?您必须处理 Apollo 错误并强制重绘整个网格 - 更改是本地的(单元格)。这可以通过 f.e. 完成。通过在 shouldComponentUpdate 中设置标志(使用 setState)和附加条件。

关于reactjs - 处理ag网格 react 并渲染复选框网格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51490792/

相关文章:

javascript - 如何检查富文本编辑器内容是否为空?

javascript - 是否可以将可选链与数组和映射(在 Javascript 中)结合起来?

reactjs - ag-grid react cellRendererFramework 在状态改变时不会重新渲染

javascript - getRowHeight() 不适用于 rowModelType = 'infinite' 和最新的 ag-grid 版本

reactjs - readQuery 不适用于 Apollo 和 GraphQL 应用程序中的分页

javascript - 如何在 React 中管理同一页面上的多个相同组件及其各自单独的 axios 请求?

reactjs - 如何在用户进入页面时自动点击按钮

reactjs - ag-Grid React applyTransaction 不是函数

caching - 大数据集的 Apollo InMemoryCache 性能策略(React)

reactjs - Apollo Optimistic UI 在 Mutation 组件中不起作用?