javascript - 如何使用 REACT 渲染/更新我的表格?

标签 javascript html reactjs react-hooks react-table

当我单击 Apply 时,我无法进行多重交叉过滤(应用我从下拉列表中选择的所有选项)或 Cancel按钮(重置所选选项)。例如按 taste 过滤和 availability (请看图片)。但我无法呈现过滤后的行/更新的表。

export default function MenuDisplay() {
  const { menuId } = useParams();
  const { match } = JsonData;
  const [selected, setSelected] = useState({});
  const [hidden, setHidden] = useState({});
  const [taste, setTaste] = useState([
    { label: "Good", value: "Good", name: "Good", selected: false },
    { label: "Medium", value: "Medium", name: "Medium", selected: false },
    { label: "Bad", value: "Bad", name: "Bad", selected: false }
  ]);

  const [comments, setComments] = useState([
    { label: "0", value: "0", name: "0", selected: false },
    { label: "1", value: "1", name: "1", selected: false },
    { label: "2", value: "2", name: "2", selected: false },
    { label: "3", value: "3", name: "3", selected: false },
    { label: "4", value: "4", name: "4", selected: false },
    { label: "5", value: "5", name: "5", selected: false }
  ]);

  const [availability, setAvailability] = useState([
    {
      label: "availability",
      value: "availability",
      name: "Availability",
      selected: false
    },
    { label: "trust", value: "trust", name: "Trust", selected: false }
  ]);

  function selectionOpt(setItems) {
    return (selection) => {
      setItems(selection);
    };
  }

  const impact = (value) => {
    if (value === 1) {
      return (
        <div>
          <TaskAltIcon />
        </div>
      );
    } else {
      return (
        <div>
          <CancelIcon />
        </div>
      );
    }
  };

  // If any row is selected, the button should be in the Apply state
  // else it should be in the Cancel state
  const buttonMode = Object.values(selected).some((isSelected) => isSelected)
    ? "apply"
    : "cancel";

  const rowSelectHandler = (id) => (checked) => {
    setSelected((selected) => ({
      ...selected,
      [id]: checked
    }));
  };

  const handleClick = () => {
    if (buttonMode === "apply") {
      // Hide currently selected items
      const currentlySelected = {};
      Object.entries(selected).forEach(([id, isSelected]) => {
        if (isSelected) {
          currentlySelected[id] = isSelected;
        }
      });
      setHidden({ ...hidden, ...currentlySelected });

      // Clear all selection
      const newSelected = {};
      Object.keys(selected).forEach((id) => {
        newSelected[id] = false;
      });
      setSelected(newSelected);
    } else {
      // Select all currently hidden items
      const currentlyHidden = {};
      Object.entries(hidden).forEach(([id, isHidden]) => {
        if (isHidden) {
          currentlyHidden[id] = isHidden;
        }
      });
      setSelected({ ...selected, ...currentlyHidden });

      // Clear all hidden items
      const newHidden = {};
      Object.keys(hidden).forEach((id) => {
        newHidden[id] = false;
      });
      setHidden(newHidden);
    }
  };

  const matchData = (
    match.find((el) => el._id_menu === menuId)?._ids ?? []
  ).filter(({ _id }) => {
    return !hidden[_id];
  });

  const getRowProps = (row) => {
    return {
      style: {
        backgroundColor: selected[row.values.id] ? "lightgrey" : "white"
      }
    };
  };

  const data = [
    {
      Header: "id",
      accessor: (row) => row._id
    },
    {
      Header: "Name",
      accessor: (row) => (
        <Link to={{ pathname: `/menu/${menuId}/${row._id}` }}>{row.name}</Link>
      )
    },
    {
      Header: "Taste",
      accessor: (row) => row.taste
    },
    {
      Header: "Comments",
      //check current row is in hidden rows or not
      accessor: (row) => {
        const comments = parseInt(row.comments, 10);

        return <Counter count={comments} />;
      }
    },
    {
      Header: "Price",
      accessor: (row) => row.price,
      id: "price"
    },
    {
      Header: "Status",
      accessor: (row) => row.status
    },
    {
      Header: "Availability",
      accessor: (row) => row.availability,
      id: "availability",
      Cell: (props) => impact(props.value)
    },
    {
      Header: "Trust",
      accessor: (row) => row.trust,
      id: "trust",
      Cell: (props) => impact(props.value)
    },
    {
      Header: "Show",
      accessor: (row) => (
        <Toggle
          value={selected[row._id]}
          onChange={rowSelectHandler(row._id)}
        />
      )
    }
  ];

  const initialState = {
    sortBy: [
      { desc: false, id: "id" },
      { desc: false, id: "description" }
    ],
    hiddenColumns: ["dishes", "id"]
  };

  return (
    <div>
      <button type="button" onClick={handleClick}>
        {buttonMode === "cancel" ? "Cancel" : "Apply"}
      </button>
      <div className="flex justify-end gap-4 ">
        <div>
          <Button>Apply</Button>
        </div>
        <div>
          <Button>Cancel</Button>
        </div>
      </div>
      Taste
      <ListDrop
        placeholder={"Select"}
        items={taste}
        onSelect={selectionOpt(setTaste)}
        hasAll
      />
      Comments
      <ListDrop
        placeholder={"Select"}
        items={comments}
        onSelect={selectionOpt(setComments)}
        hasAll
      />
      <p>Availability & Trust </p>
      {/* I would like to have in my dropdown Availability and Trust as 
           options in my dropdown and it refers to the cross where availaibility: 1 and trust:1 ) */}
      <ListDrop
        placeholder={"Select"}
        items={availability}
        onSelect={selectionOpt(setAvailability)}
        hasAll
      />
      <Table
        data={matchData}
        columns={data}
        initialState={initialState}
        withCellBorder
        withRowBorder
        withSorting
        withPagination
        rowProps={getRowProps}
      />
    </div>
  );
}
请查看我的codeSandbox
请检查图片以获得一个想法:
enter image description here

最佳答案

我选择了一些字段并为您创建了一个简单的应用程序,如果您仔细阅读代码,您将弄清楚它是如何工作的,然后您可以类似地更改您的代码:

table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

import React, { useEffect } from "react";
import "./styles.css";

const soupsData = [
  {
    name: "Pea Soup",
    taste: "Good",
    trust: 1,
    availability: 0
  },
  {
    name: "Potato Soup ",
    taste: "Medium",
    trust: 1,
    availability: 1
  },
  {
    name: "Cucumber Soup ",
    taste: "Medium",
    trust: 1,
    availability: 1
  }
];

const tasteOptions = [
  { label: "Good", name: "Good" },
  { label: "Medium", name: "Medium" },
  { label: "Bad", name: "Bad" }
];

const availabilityAndTrustOptions = [
  {
    name: "all",
    label: "all"
  },
  {
    name: "availability",
    label: "availability"
  },
  {
    name: "trust",
    label: "trust"
  }
];

function App() {
  const [soups, setSoups] = React.useState([]);
  const [tastes, setTastes] = React.useState([]);
  const [availabilityAndTrust, setAvailabilityAndTrust] = React.useState({
    trust: 0,
    availability: 0
  });

  useEffect(() => {

    const filteredSoups = soupsData.filter((soup) => {
      const availability = availabilityAndTrust.availability;
      const trust = availabilityAndTrust.trust;

      if (availability) {
        if (!soup.availability) return false;
      }

      if (trust) {
        if (!soup.trust) return false;
      }

      if (tastes.length > 0) {
        if (!tastes.includes(soup.taste)) return false;
      }

      return true;
    });

    setSoups(() => filteredSoups);
  }, [tastes, availabilityAndTrust]);

  const handleTasteChange = (e) => {
    const targetTaste = e.target.name;
    if (tastes.includes(targetTaste)) {
      setTastes(() => tastes.filter((taste) => taste !== targetTaste));
    } else setTastes((prevData) => [...prevData, targetTaste]);
  };

  const handleAvailabilityAndTrustChange = (e) => {
    const targetName = e.target.name;
    switch (targetName) {
      case "all":
        setAvailabilityAndTrust((prevData) => {
          if (prevData.trust && prevData.availability) {
            return {
              trust: 0,
              availability: 0
            };
          }
          if (prevData.trust || prevData.availability) {
            return {
              trust: 1,
              availability: 1
            };
          }
          return {
            trust: 1,
            availability: 1
          };
        });
        break;
      case "availability":
        setAvailabilityAndTrust((prevData) => {
          return {
            trust: prevData.trust,
            availability: prevData.availability ? 0 : 1
          };
        });
        break;
      case "trust":
        setAvailabilityAndTrust((prevData) => {
          return {
            trust: prevData.trust ? 0 : 1,
            availability: prevData.availability
          };
        });
        break;
      default:
    }
  };

  return (
    <div>
      <div>
        <div>Taste</div>
        {tasteOptions.map((taste) => {
          return (
            <div>
              <label for={taste.label}>{taste.label}</label>
              <input
                name={taste.name}
                onChange={handleTasteChange}
                id={taste.label}
                type="checkbox"
              />
            </div>
          );
        })}
      </div>
      <br />
      <div>
        <div>Availability & Trust</div>
        {availabilityAndTrustOptions.map((option) => {
          return (
            <div>
              <label for={option.label}>{option.label}</label>
              <input
                name={option.name}
                checked={(() => {
                  switch (option.label) {
                    case "all":
                      return (
                        availabilityAndTrust.availability &&
                        availabilityAndTrust.trust
                      );
                    case "availability":
                      return availabilityAndTrust.availability;
                    case "trust":
                      return availabilityAndTrust.trust;
                    default:
                      return false;
                  }
                })()}
                onChange={handleAvailabilityAndTrustChange}
                id={option.label}
                type="checkbox"
              />
            </div>
          );
        })}
      </div>
      <br />
      <table>
        <tr>
          <th>Name</th>
          <th>Taste</th>
          <th>Trust</th>
          <th>Availability</th>
        </tr>
        {soups.map((soup) => {
          return (
            <tr>
              <td>{soup.name}</td>
              <td>{soup.taste}</td>
              <td>{soup.trust}</td>
              <td>{soup.availability}</td>
            </tr>
          );
        })}
      </table>
    </div>
  );
}

您应该使用 useState 来存储可能在运行时更改并具有渲染效果的数据。
我使用 useEffect 根据选项更改过滤表格的内容。
密码箱:https://codesandbox.io/s/serene-shamir-lns51i

关于javascript - 如何使用 REACT 渲染/更新我的表格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72736330/

相关文章:

javascript - 将标记与 jsx 结合起来

javascript - 如何从外部访问 React 组件中使用的第三方 DOM 库中的对象属性

javascript - jquery比较同一行的数据,如果正确则显示第三行的内容

php - 将图像从数据库 MySql 加载到 Bootstrap 轮播中

javascript - react .js : Avoid updates of currently edited input

html - 使内容放在左侧菜单旁边而不是放在下面

html - 从 multer 返回未定义的答案

javascript - css网格填充100vh而不影响行高

javascript - AngularJS:取消订阅事件

javascript - Jest/Enzyme 图像加载回调未运行