【问题标题】:Synchronize Material UI switches with MaterialTable columns将 Material UI 开关与 MaterialTable 列同步
【发布时间】:2021-03-16 19:48:14
【问题描述】:

更改列的hidden 状态后,我无法重新渲染网格。我认为修改 columns 会导致网格重新渲染,因为它是一个绑定属性。

这是一个在codesandbox.io 托管的交互式示例。

index.jsx

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

App.js

import React from "react";
import SuperTable from "./components/SuperTable";

const data = [
  { id: 1, type: "Developer", name: "Bob", age: 21 },
  { id: 2, type: "Developer", name: "Mary", age: 28 },
  { id: 3, type: "Manager", name: "Steve", age: 42 }
];

const columns = [
  {
    field: "id",
    title: "ID",
    searchable: true,
    hidden: true
  },
  {
    field: "name",
    title: "Name",
    searchable: true
  },
  {
    field: "age",
    title: "Age",
    searchable: true
  },
  {
    field: "type",
    title: "Type",
    searchable: true
  }
];

const App = () => {
  return <SuperTable data={data} columns={columns} />;
};

export default App;

SuperTable.jsx

import MaterialTable from "material-table";
import React, { forwardRef } from "react";
import { makeStyles } from "@material-ui/core/styles";
import ArrowDownward from "@material-ui/icons/ArrowDownward";
import ChevronLeft from "@material-ui/icons/ChevronLeft";
import ChevronRight from "@material-ui/icons/ChevronRight";
import ClearIcon from "@material-ui/icons/Clear";
import FirstPage from "@material-ui/icons/FirstPage";
import LastPage from "@material-ui/icons/LastPage";
import Search from "@material-ui/icons/Search";
import ColumnToggler from "./ColumnToggler";

const useStyles = makeStyles((theme) => ({
  wrapper: {
    display: "flex",
    flexDirection: "row"
  },
  widget: {
    display: "flex",
    flexDirection: "column",
    flex: 0.5
  }
}));

const tableIcons = {
  ResetSearch: forwardRef((props, ref) => <ClearIcon {...props} ref={ref} />),
  FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
  LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
  NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
  PreviousPage: forwardRef((props, ref) => (
    <ChevronLeft {...props} ref={ref} />
  )),
  Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
  SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />)
};

const SuperTable = (props) => {
  const { data, columns, ...rest } = props;

  const classes = useStyles();

  const onToggle = (columnField, show) => {
    const foundColumn = columns.find((col) => col.field === columnField);
    if (foundColumn) {
      foundColumn.hidden = show;
    }
  };

  return (
    <div className={classes.wrapper}>
      <MaterialTable
        style={{
          position: "unset",
          display: "flex",
          flexDirection: "column",
          flex: 1
        }}
        title={null}
        data={data}
        columns={columns}
        icons={tableIcons}
        pageSize={5}
        {...rest}
      />
      <div className={classes.widget}>
        <ColumnToggler onChange={onToggle} columns={columns} />
      </div>
    </div>
  );
};

SuperTable.propTypes = {
  ...MaterialTable.propTypes
};

export default SuperTable;

ColumnToggler.jsx

import React from "react";
import { Typography } from "@material-ui/core";
import PropTypes from "prop-types";
import { Container, makeStyles } from "@material-ui/core";
import ColumnToggleSwitch from "./ColumnToggleSwitch";

const useStyles = makeStyles((theme) => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 200
  }
}));

const ColumnToggler = (props) => {
  const { columns, onChange } = props;

  const classes = useStyles();

  const toggleChecked = (field, show) => {
    onChange(field, show);
  };

  console.log("Updated toggler...");

  return (
    <Container className={classes.formControl}>
      <Typography>Toggle Columns</Typography>
      {columns.map((column) => (
        <ColumnToggleSwitch column={column} onChange={toggleChecked} />
      ))}
    </Container>
  );
};

ColumnToggler.propTypes = {
  onChange: PropTypes.func.isRequired
};

export default ColumnToggler;

ColumnToggleSwitch.jsx

import React, { useState } from "react";
import PropTypes from "prop-types";
import { FormControlLabel, FormGroup, Switch } from "@material-ui/core";

const ColumnToggleSwitch = (props) => {
  const {
    column: { field, hidden, title },
    onChange
  } = props;
  const [checked, setChecked] = useState(hidden == null || !hidden);

  const handleChange = (event, newValue) => {
    setChecked(newValue);
    onChange(event.currentTarget.name, newValue);
  };

  return (
    <FormGroup>
      <FormControlLabel
        control={
          <Switch
            key={field}
            name={field}
            checked={checked}
            onChange={handleChange}
            color="primary"
            inputProps={{ "aria-label": "primary checkbox" }}
            size="small"
          />
        }
        label={title || field}
      />
    </FormGroup>
  );
};

ColumnToggleSwitch.propTypes = {
  column: PropTypes.object.isRequired,
  onChange: PropTypes.func.isRequired
};

export default ColumnToggleSwitch;

package.json

{
  "dependencies": {
    "@material-ui/core": "4.11.2",
    "@material-ui/icons": "4.11.2",
    "material-table": "1.69.2",
    "react": "17.0.0",
    "react-dom": "17.0.0",
    "react-scripts": "3.4.3"
  }
}

【问题讨论】:

    标签: javascript reactjs data-binding


    【解决方案1】:

    主要问题在于 React 中的 props 是不可变的。如果您修改组件中的某个 prop,该值将不保证重新渲染。

    您正在更改您的 columns 组件中的 columns 属性,并且无法正常工作。

    解决方案是将列定义为常量,将其导入并将其设置为columns 状态的初始状态。 columns 无论如何都是一个常数,它不必作为道具发送。

    components/columns.js:

    // define columns and export it
    

    SuperTable.jsx:

    import initialColumns from './columns';
    
    ...
    const [columns, setColumns] = useState(initialColumns);
    

    状态也是不可变的,所以你不应该这样做:

    foundColumn.hidden = show;
    

    但应该这样做:

    const newColumns = ....;
    setColumns(newColumns);
    

    【讨论】:

    • 我注意到,如果我尝试取消隐藏隐藏列,控制台中会抛出错误。我意识到隐藏列的列数据没有分配计算宽度。我只是编造了自己的宽度,它可以工作。这是解决这个问题的最好方法吗?请参阅我更新的(工作)示例。此外,列最终将是动态的,因此常量将不起作用...Material UI Table Column Toggle 2.0
    猜你喜欢
    • 1970-01-01
    • 2021-01-29
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 2021-01-20
    • 2015-10-08
    相关资源
    最近更新 更多