【问题标题】:Material UI menu button inside a table with pagination and sort does not work after second page带有分页和排序的表格内的 Material UI 菜单按钮在第二页后不起作用
【发布时间】:2021-08-27 04:49:47
【问题描述】:

我正在使用 React 并使用 Material UI。 我正在构建一个包含多列和多行的表格,每行中的一个单元格是一个菜单按钮,一旦单击它就会打开。

在我向表格添加分页和排序之前,这一切正常。 添加分页和排序后,每行的菜单只会在分页的第一页打开。

似乎在第二页之后,菜单会打开但它没有出现在页面上。它的位置似乎较低,但由于分页,我看不到它。

在使用带有分页的表格时,我如何才能看到位于第二页和之后的行的菜单? 排序时如何在页面中看到菜单?

非常感谢您的帮助。

代码:

import React, { useContext, useState } from "react";

import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TablePagination from "@material-ui/core/TablePagination";
import TableSortLabel from "@material-ui/core/TableSortLabel";
import Paper from "@material-ui/core/Paper";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";

import useStyles from "./../styles/tableStyles";
import CurrenciesContext from "./../context/currenciesContext";
import DeleteCurrencyContext from "./../context/deleteCurrencyContext";
import AddToCompareContext from "./../context/addToCompareContext";

function descendingComparator(a, b, orderBy) {
  if (b[orderBy] < a[orderBy]) {
    return -1;
  }
  if (b[orderBy] > a[orderBy]) {
    return 1;
  }
  return 0;
}

function getComparator(order, orderBy) {
  return order === "desc"
    ? (a, b) => descendingComparator(a, b, orderBy)
    : (a, b) => -descendingComparator(a, b, orderBy);
}

function stableSort(array, comparator) {
  const stabilizedThis = array.map((el, index) => [el, index]);
  stabilizedThis.sort((a, b) => {
    const order = comparator(a[0], b[0]);
    if (order !== 0) return order;
    return a[1] - b[1];
  });
  return stabilizedThis.map((el) => el[0]);
}

const CurrencyTable = () => {
  const BILLION = 1000000000;
  const TRILLION = 1000000000000;
  const MILLION = 1000000;

  const classes = useStyles();

  const currencies = useContext(CurrenciesContext);
  const addToCompare = useContext(AddToCompareContext);
  const deleteCurrency = useContext(DeleteCurrencyContext);

  const [openTableMenus, setOpenTableMenus] = useState([]);
  const [rowsPerPage, setRowsPerPage] = useState(5);
  const [page, setPage] = useState(0);
  const [order, setOrder] = useState("asc");
  const [orderBy, setOrderBy] = useState("rank");

  const handleClickTableMenu = (currency, event) => {
    let tableMenus = [...openTableMenus];
    const index = currencies.indexOf(currency);
    tableMenus[index] = event.currentTarget;
    setOpenTableMenus(tableMenus);
  };

  const handleCloseTableMenu = (currency) => {
    let tableMenus = [...openTableMenus];
    const index = currencies.indexOf(currency);
    tableMenus[index] = null;
    setOpenTableMenus(tableMenus);
  };

  const handleTranformBigNum = (num) => {
    if (Math.round(num).toString().length > 12)
      return `${(num / TRILLION).toFixed(2)}T`;
    if (Math.round(num).toString().length > 9)
      return `${(num / BILLION).toFixed(2)}B`;
    if (Math.round(num).toString().length > 6)
      return `${(num / MILLION).toFixed(2)}M`;
    return num.toFixed(2);
  };

  const handleChangePage = (event, newPage) => {
    setPage(newPage);
  };

  const handleChangeRowsPerPage = (event) => {
    setRowsPerPage(parseInt(event.target.value, 10));
    setPage(0);
  };

  const handleRequestSort = (event, property) => {
    const isAsc = orderBy === property && order === "asc";
    setOrder(isAsc ? "desc" : "asc");
    setOrderBy(property);
  };

  const createSortHandler = (property) => (event) => {
    handleRequestSort(event, property);
  };

  const handleDeleteCurrency = (currency) => {
    console.log("delete", currency);
    deleteCurrency(currency);
  };

  const headCells = [
    {
      id: "rank",
      label: "#",
    },
    {
      id: "name",
      label: "Name",
    },
    {
      id: "priceChange1d",
      label: "24H Change",
    },
    {
      id: "price",
      label: "Price",
    },
    {
      id: "priceBtc",
      label: "Price in BTC",
    },
    {
      id: "marketCap",
      label: "Market CAP",
    },
    {
      id: "volume",
      label: "Volume 24H",
    },
  ];

  console.log("menus anchors: ", openTableMenus);

  return (
    <React.Fragment>
      <h2>Currencies Table</h2>
      <TableContainer component={Paper}>
        <Table className={classes.table} aria-label="simple table">
          <TableHead>
            <TableRow>
              {headCells.map((headCell) => (
                <TableCell
                  key={headCell.id}
                  align="center"
                  sortDirection={orderBy === headCell.id ? order : false}
                >
                  <TableSortLabel
                    active={orderBy === headCell.id}
                    direction={orderBy === headCell.id ? order : "asc"}
                    onClick={createSortHandler(headCell.id)}
                  >
                    {headCell.label}
                  </TableSortLabel>
                </TableCell>
              ))}
              <TableCell align="center">PRICE GRAPH (7D)</TableCell>
              <TableCell align="center"></TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {currencies &&
              stableSort(currencies, getComparator(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map((currency, index) => (
                  <TableRow key={currency.id}>
                    <TableCell component="th" scope="row">
                      {currency.rank}
                    </TableCell>
                    <TableCell align="center">
                      {currency.name}
                      <span className={classes.grey}>-{currency.symbol}</span>
                    </TableCell>
                    <TableCell
                      align="center"
                      className={
                        currency.priceChange1d >= 0
                          ? classes.positiveChange
                          : classes.negativeChange
                      }
                    >{`${currency.priceChange1d}%`}</TableCell>
                    <TableCell align="center">
                      {`$${currency.price.toFixed(2)}`}
                    </TableCell>
                    <TableCell align="center">{currency.priceBtc}</TableCell>
                    <TableCell align="center">
                      {handleTranformBigNum(currency.marketCap)}
                    </TableCell>
                    <TableCell align="center">
                      {handleTranformBigNum(currency.volume)}
                    </TableCell>
                    <TableCell align="center">GRAPH</TableCell>
                    <TableCell align="center">
                      <IconButton
                        aria-label={`${currency.name}-more`}
                        aria-controls={`${currency.name}-menu`}
                        aria-haspopup="true"
                        onClick={(event) =>
                          handleClickTableMenu(currency, event)
                        }
                      >
                        <MenuIcon />
                      </IconButton>
                      <Menu
                        id={`${currency.name}-menu`}
                        anchorEl={openTableMenus[index]}
                        keepMounted
                        open={Boolean(openTableMenus[index])}
                        onClose={(event) => handleCloseTableMenu(currency)}
                      >
                        <MenuItem
                          onClick={(event) => {
                            handleCloseTableMenu(currency);
                            addToCompare(currency);
                          }}
                        >
                          Add to Compare
                        </MenuItem>
                        <MenuItem
                          onClick={() => {
                            handleCloseTableMenu(currency);
                            handleDeleteCurrency(currency);
                          }}
                        >
                          Delete Row
                        </MenuItem>
                      </Menu>
                    </TableCell>
                  </TableRow>
                ))}
          </TableBody>
        </Table>
      </TableContainer>
      <TablePagination
        rowsPerPageOptions={[5, 10, 25, 50]}
        component="div"
        count={currencies.length}
        rowsPerPage={rowsPerPage}
        page={page}
        onChangePage={(event, newPage) => handleChangePage(event, newPage)}
        onChangeRowsPerPage={(event) => handleChangeRowsPerPage(event)}
      />
    </React.Fragment>
  );
};

export default CurrencyTable;

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    我想通了。 它与使用分页后的列表索引有关。 使用分页时,列表中项目的索引将始终从 0 到每页的项目数,而不是分页前项目在列表中的原始索引。

    如果您也遇到此问题,请参阅以下代码以查看答案。

    import React, { useContext, useState } from "react";
    
    import Table from "@material-ui/core/Table";
    import TableBody from "@material-ui/core/TableBody";
    import TableCell from "@material-ui/core/TableCell";
    import TableContainer from "@material-ui/core/TableContainer";
    import TableHead from "@material-ui/core/TableHead";
    import TableRow from "@material-ui/core/TableRow";
    import TablePagination from "@material-ui/core/TablePagination";
    import TableSortLabel from "@material-ui/core/TableSortLabel";
    import Paper from "@material-ui/core/Paper";
    import Menu from "@material-ui/core/Menu";
    import MenuItem from "@material-ui/core/MenuItem";
    import MenuIcon from "@material-ui/icons/Menu";
    import IconButton from "@material-ui/core/IconButton";
    
    import useStyles from "./../styles/tableStyles";
    import CurrenciesContext from "./../context/currenciesContext";
    import DeleteCurrencyContext from "./../context/deleteCurrencyContext";
    import AddToCompareContext from "./../context/addToCompareContext";
    
    function descendingComparator(a, b, orderBy) {
      if (b[orderBy] < a[orderBy]) {
        return -1;
      }
      if (b[orderBy] > a[orderBy]) {
        return 1;
      }
      return 0;
    }
    
    function getComparator(order, orderBy) {
      return order === "desc"
        ? (a, b) => descendingComparator(a, b, orderBy)
        : (a, b) => -descendingComparator(a, b, orderBy);
    }
    
    function stableSort(array, comparator) {
      const stabilizedThis = array.map((el, index) => [el, index]);
      stabilizedThis.sort((a, b) => {
        const order = comparator(a[0], b[0]);
        if (order !== 0) return order;
        return a[1] - b[1];
      });
      return stabilizedThis.map((el) => el[0]);
    }
    
    const CurrencyTable = () => {
      const BILLION = 1000000000;
      const TRILLION = 1000000000000;
      const MILLION = 1000000;
    
      const classes = useStyles();
    
      const currencies = useContext(CurrenciesContext);
      const addToCompare = useContext(AddToCompareContext);
      const deleteCurrency = useContext(DeleteCurrencyContext);
    
      const [openTableMenus, setOpenTableMenus] = useState([]);
      const [rowsPerPage, setRowsPerPage] = useState(5);
      const [page, setPage] = useState(0);
      const [order, setOrder] = useState("asc");
      const [orderBy, setOrderBy] = useState("rank");
    
      const handleClickTableMenu = (currency, index, event) => {
        let tableMenus = [...openTableMenus];
        tableMenus[index] = event.currentTarget;
        setOpenTableMenus(tableMenus);
      };
    
      const handleCloseTableMenu = (index) => {
        let tableMenus = [...openTableMenus];
        tableMenus[index] = null;
        setOpenTableMenus(tableMenus);
      };
    
      const handleTranformBigNum = (num) => {
        if (Math.round(num).toString().length > 12)
          return `${(num / TRILLION).toFixed(2)}T`;
        if (Math.round(num).toString().length > 9)
          return `${(num / BILLION).toFixed(2)}B`;
        if (Math.round(num).toString().length > 6)
          return `${(num / MILLION).toFixed(2)}M`;
        return num.toFixed(2);
      };
    
      const handleChangePage = (event, newPage) => {
        setPage(newPage);
      };
    
      const handleChangeRowsPerPage = (event) => {
        setRowsPerPage(parseInt(event.target.value, 10));
        setPage(0);
      };
    
      const handleRequestSort = (event, property) => {
        const isAsc = orderBy === property && order === "asc";
        setOrder(isAsc ? "desc" : "asc");
        setOrderBy(property);
      };
    
      const createSortHandler = (property) => (event) => {
        handleRequestSort(event, property);
      };
    
      const handleDeleteCurrency = (currency) => {
        deleteCurrency(currency);
      };
    
      const headCells = [
        {
          id: "rank",
          label: "#",
        },
        {
          id: "name",
          label: "Name",
        },
        {
          id: "priceChange1d",
          label: "24H Change",
        },
        {
          id: "price",
          label: "Price",
        },
        {
          id: "priceBtc",
          label: "Price in BTC",
        },
        {
          id: "marketCap",
          label: "Market CAP",
        },
        {
          id: "volume",
          label: "Volume 24H",
        },
      ];
    
      return (
        <React.Fragment>
          <h2>Currencies Table</h2>
          <TableContainer component={Paper}>
            <Table className={classes.table} aria-label="simple table">
              <TableHead>
                <TableRow>
                  {headCells.map((headCell) => (
                    <TableCell
                      key={headCell.id}
                      align="center"
                      sortDirection={orderBy === headCell.id ? order : false}
                    >
                      <TableSortLabel
                        active={orderBy === headCell.id}
                        direction={orderBy === headCell.id ? order : "asc"}
                        onClick={createSortHandler(headCell.id)}
                      >
                        {headCell.label}
                      </TableSortLabel>
                    </TableCell>
                  ))}
                  <TableCell align="center"></TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {currencies &&
                  stableSort(currencies, getComparator(order, orderBy))
                    .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                    .map((currency, index) => (
                      <TableRow key={currency.id}>
                        <TableCell component="th" scope="row">
                          {currency.rank}
                        </TableCell>
                        <TableCell align="center">
                          <div className={classes.icon}>
                            <img
                              src={currency.icon}
                              alt={`${currency.name} icon`}
                              width="25"
                              height="25"
                            ></img>
                          </div>
                          {currency.name}
                          <span className={classes.grey}>-{currency.symbol}</span>
                        </TableCell>
                        <TableCell
                          align="center"
                          className={
                            currency.priceChange1d >= 0
                              ? classes.positiveChange
                              : classes.negativeChange
                          }
                        >{`${currency.priceChange1d}%`}</TableCell>
                        <TableCell align="center">
                          {`$${currency.price.toFixed(2)}`}
                        </TableCell>
                        <TableCell align="center">{currency.priceBtc}</TableCell>
                        <TableCell align="center">
                          {handleTranformBigNum(currency.marketCap)}
                        </TableCell>
                        <TableCell align="center">
                          {handleTranformBigNum(currency.volume)}
                        </TableCell>
                        <TableCell align="center">
                          <IconButton
                            aria-label={`${currency.name}-more`}
                            aria-controls={`${currency.name}-menu`}
                            aria-haspopup="true"
                            onClick={(event) =>
                              handleClickTableMenu(currency, index, event)
                            }
                          >
                            <MenuIcon />
                          </IconButton>
                          <Menu
                            id={`${currency.name}-menu`}
                            anchorEl={openTableMenus[index]}
                            keepMounted
                            open={Boolean(openTableMenus[index])}
                            onClose={(event) => handleCloseTableMenu(index)}
                          >
                            <MenuItem
                              onClick={(event) => {
                                handleCloseTableMenu(index);
                                addToCompare(currency);
                              }}
                            >
                              Add to Compare
                            </MenuItem>
                            <MenuItem
                              onClick={() => {
                                handleCloseTableMenu(index);
                                handleDeleteCurrency(currency);
                              }}
                            >
                              Delete Row
                            </MenuItem>
                          </Menu>
                        </TableCell>
                      </TableRow>
                    ))}
              </TableBody>
            </Table>
          </TableContainer>
          <TablePagination
            rowsPerPageOptions={[5, 10, 25, 50]}
            component="div"
            count={currencies.length}
            rowsPerPage={rowsPerPage}
            page={page}
            onChangePage={(event, newPage) => handleChangePage(event, newPage)}
            onChangeRowsPerPage={(event) => handleChangeRowsPerPage(event)}
          />
        </React.Fragment>
      );
    };
    
    export default CurrencyTable;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-25
      • 2019-12-30
      • 2018-03-24
      • 2016-03-25
      • 2021-08-22
      • 2019-01-27
      • 1970-01-01
      • 2020-11-18
      相关资源
      最近更新 更多