【问题标题】:How check the state of individual checkbox in reactjs (material-table)如何检查 reactjs 中单个复选框的状态(材料表)
【发布时间】:2022-01-13 22:20:36
【问题描述】:

我有一个表,其中包含从数据库中获取的学生列表。当我单击每个学生行时,将显示一个模式弹出窗口,其中包含另一个 4 行和 3 列的表。模式中的每一列将包含 4 个复选框。当我单击一个复选框时,我想将该行的状态列从“待定”更改为“已付款”,并将徽章属性类型从“危险”更改为“成功”。问题是当我单击一个复选框时,它会将所有列的状态从“待定”更改为“已付款”,而不仅仅是更改单行。

这是我的代码

import {
  Table,
  TableBody,
  TableCell,
  Badge,
  TableFooter,
  TableRow,
  TableHeader,
  TableContainer,
  Input,
  Modal,
  ModalHeader,
  ModalBody,
  ModalFooter,
  Button,
} from "@windmill/react-ui";
import MaterialTable from "material-table";
import AddBox from "@material-ui/icons/AddBox";
import ArrowDownward from "@material-ui/icons/ArrowDownward";
import Check from "@material-ui/icons/Check";
import ChevronLeft from "@material-ui/icons/ChevronLeft";
import ChevronRight from "@material-ui/icons/ChevronRight";
import Clear from "@material-ui/icons/Clear";
import DeleteOutline from "@material-ui/icons/DeleteOutline";
import Edit from "@material-ui/icons/Edit";
import FilterList from "@material-ui/icons/FilterList";
import FirstPage from "@material-ui/icons/FirstPage";
import LastPage from "@material-ui/icons/LastPage";
import Remove from "@material-ui/icons/Remove";
import SaveAlt from "@material-ui/icons/SaveAlt";

import Search from "@material-ui/icons/Search";
import ViewColumn from "@material-ui/icons/ViewColumn";
import React, { forwardRef, useState } from "react";
const Admin = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [id, setId] = useState("");

  function openModal(ids) {
    setId(ids.studentId);
    setIsModalOpen(true);
  }
  function closeModal() {
    setIsModalOpen(false);
  }

  const tableIcons = {
    Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
    Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
    Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
    DetailPanel: forwardRef((props, ref) => (
      <ChevronRight {...props} ref={ref} />
    )),
    Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
    Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
    Filter: forwardRef((props, ref) => <FilterList {...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} />
    )),
    ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
    SortArrow: forwardRef((props, ref) => (
      <ArrowDownward {...props} ref={ref} />
    )),
    ThirdStateCheck: forwardRef((props, ref) => (
      <Remove {...props} ref={ref} />
    )),
    ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />),
  };
  const [status, setStatus] = useState("pending");
  const [badge, setBadge] = useState("danger");

  const handleClick = (e) => {
    //Do something if checkbox is clicked
    if (e.target.checked) {
      setStatus("paid");
      setBadge("success");
    } else {
      setStatus("pending");
      setBadge("danger");
    }
  };

  // Table to be rendered in the modal
  function renderTable() {
    return (
      <TableContainer>
        <Table>
          <TableHeader>
            <TableRow>
              <TableCell>Dues</TableCell>
              <TableCell>Amount</TableCell>
              <TableCell>Status</TableCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            <TableRow>
              <TableCell>
                <div className='flex items-center text-sm'>
                  <span className='font-semibold ml-2'>Level 100</span>
                </div>
              </TableCell>
              <TableCell>
                <span className='text-sm'>100</span>
              </TableCell>
              <TableCell>
                <Badge type={badge}>{status}</Badge>
                <Input
                  type='checkbox'
                  className='ml-6'
                  onClick={(e) => handleClick(e)}
                />
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell>
                <div className='flex items-center text-sm'>
                  <span className='font-semibold ml-2'>Level 200</span>
                </div>
              </TableCell>
              <TableCell>
                <span className='text-sm'>100</span>
              </TableCell>
              <TableCell>
                <Badge type={badge}>{status}</Badge>
                <Input
                  type='checkbox'
                  className='ml-6'
                  onClick={(e) => handleClick(e)}
                />
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell>
                <div className='flex items-center text-sm'>
                  <span className='font-semibold ml-2'>Level 300</span>
                </div>
              </TableCell>
              <TableCell>
                <span className='text-sm'>100</span>
              </TableCell>
              <TableCell>
                <Badge type={badge}>{status}</Badge>
                <Input
                  type='checkbox'
                  className='ml-6'
                  onClick={(e) => handleClick(e)}
                />
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell>
                <div className='flex items-center text-sm'>
                  <span className='font-semibold ml-2'>Level 400</span>
                </div>
              </TableCell>
              <TableCell>
                <span className='text-sm'>100</span>
              </TableCell>
              <TableCell>
                <Badge type={badge}>{status}</Badge>
                <Input
                  type='checkbox'
                  className='ml-6'
                  onClick={(e) => handleClick(e)}
                />
              </TableCell>
            </TableRow>
          </TableBody>
        </Table>
        <TableFooter></TableFooter>
      </TableContainer>
    );
  }

  return (
    <React.Fragment>
      {/* Modal popup */}
      <Modal isOpen={isModalOpen} onClose={closeModal}>
        <ModalHeader>{id}</ModalHeader>
        <ModalBody>{renderTable()}</ModalBody>
        <ModalFooter>
          <Button
            className='w-full sm:w-auto'
            layout='outline'
            onClick={closeModal}>
            Cancel
          </Button>
          <Button className='w-full sm:w-auto'>Accept</Button>
        </ModalFooter>
      </Modal>

      <MaterialTable
        icons={tableIcons}
        columns={[
          { title: "Student ID", field: "studentId" },
          { title: "Level", field: "level" },
          { title: "Programme", field: "programme" },
        ]}
        data={[
          {
            studentId: "UG0222021",
            level: "200",
            programme: "BCOM",
          },
          {
            studentId: "UG0199821",
            level: "200",
            programme: "BCOM",
          },
        ]}
        title='Students Information'
        onRowClick={(event, rowData) => openModal(rowData)}
      />
    </React.Fragment>
  );
};
export default Admin;

【问题讨论】:

    标签: javascript reactjs checkbox material-ui material-table


    【解决方案1】:

    这是一种更通用的方法,我冒昧地使用了打字稿,因为它更容易显示正在发生的事情。

     const initialStatuses = {
      inputLevel100: "pending",
      inputLevel200: "pending",
      inputLevel300: "pending",
      inputLevel400: "pending",
     }
    
     const initialBadges = {
      inputLevel100: "danger",
      inputLevel200: "danger",
      inputLevel300: "danger",
      inputLevel400: "danger",
     }
    
     const [status, setStatus] = React.useState<{ [key: string]: string }>(initialBadges);
     const [badge, setBadge] = React.useState<{ [key: string]: string }>(initialStatuses);
    
     const handleClick = (e: { target: { checked: boolean; name: string} }) => {
     const name = e.target.name;
    
     if (e.target.checked) {
      setBadge({
        ...badge,
        [name]: "success",
      });
      
      setStatus({
       ...status,
       [name]: "paid",
      });
     }  
    
    }; 
    

    你可以通过简单的说来获得状态或徽章的价值

    status["Level200"] // Should return either "pending" or "paid"
    

    badge["Level200"] // Should return either "danger" or "success"
    

    这应该非常高效(请参阅Performance of key lookup in JavaScript object 了解更多信息)

    但是,更重要的是,您现在有了一种添加更多状态和徽章的通用方法,而不必担心为每个新添加的状态或徽章添加 useState

    另外,这种方法的另一个额外优势是,您可以(比如说)从远程 api 获取状态和徽章列表,或者(比如说)拥有一个包含状态列表和 badges.jsstatuses.js 文件客户端上的文件,然后您可以对其进行映射。然后,这使您的代码更容易扩展,并且删除/添加新状态和徽章变得微不足道

    【讨论】:

      【解决方案2】:

      这仅仅是因为您对所有状态徽章都使用了一种状态。您应该使用不同的状态来管理每个徽章。您可以将name 属性添加到每个输入,以便您可以在handleClick 函数中查看哪个输入正在更改,然后更新相关状态。您可以添加以下代码:

      /* states */
      const[statusOfLevel100, setStatusOfLevel100] = useState('pending')
      const[statusOfLevel200, setStatusOfLevel200] = useState('pending')
      const[statusOfLevel300, setStatusOfLevel300] = useState('pending')
      const[statusOfLevel400, setStatusOfLevel400] = useState('pending')
      const[badgeOfLevel100, setBadgeOfLevel100] = useState('danger')
      const[badgeOfLevel200, setBadgeOfLevel200] = useState('danger')
      const[badgeOfLevel300, setBadgeOfLevel300] = useState('danger')
      const[badgeOfLevel400, setBadgeOfLevel400] = useState('danger')
      ...
      /* handleClick function */
      const handleClick = (e) => {
      switch (e.target.name) {
        case 'inputLevel100':
          if(e.target.checked) {
            setStatusOfLevel100('paid')
            setBadgeOfLevel100('success')
          } else {
            setStatusOfLevel100('pending')
            setBadgeOfLevel100('danger')
          }
          break;
      case 'inputLevel200':
          if(e.target.checked) {
            setStatusOfLevel200('paid')
            setBadgeOfLevel200('success')
          } else {
            setStatusOfLevel200('pending')
            setBadgeOfLevel200('danger')
          }
          break;
      case 'inputLevel300':
          if(e.target.checked) {
            setStatusOfLevel300('paid')
            setBadgeOfLevel300('success')
          } else {
            setStatusOfLevel300('pending')
            setBadgeOfLevel300('danger')
          }
          break;
      case 'inputLevel400':
          if(e.target.checked) {
            setStatusOfLevel400('paid')
            setBadgeOfLevel400('success')
          } else {
            setStatusOfLevel400('pending')
            setBadgeOfLevel400('danger')
          }
          break;
      }
      

      【讨论】:

      • 这仅部分有效。当我单击一行的复选框时,它会起作用,但也会影响其他行的复选框。所以说如果我点击level100的复选框,它会从pending变为payed,但其他行的level100也会受到影响,因为它们都使用相同的状态。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 2013-05-08
      • 2021-02-09
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      • 2019-12-11
      相关资源
      最近更新 更多