1

我正在创建一个表格,一旦您单击一行,就会打开一个弹出模式,允许您更新该行的内容。模态的关闭顺序会更新更改的firestore,并激活一个道具功能,该功能将更改更新到上述组件中。

关闭模态不会更新表格(我开始意识到它根本不会导致组件重新渲染......)

成分:

父亲上桌:

import React, { Component } from "react";
import { db } from "../../firebase/firebase";
import InventoryTable from "./Table/InventoryTable";

class InventoryPage extends Component {
  constructor(props) {
    super(props);

    this.state = {
      filterGroups: [],
      data: [],
      originalData: [],
    };
    this.modalUpdate = this.modalUpdate.bind(this);
    this.filterGroupToggle = this.filterGroupToggle.bind(this);
  }

  modalUpdate(modifiedRow) {
    let newData = this.state.data;
    let oldRow = newData.filter((row) => {
      return row.id === modifiedRow.id;
    });
    let oldRowIndex = newData.indexOf(...oldRow);
    newData.splice(oldRowIndex, 1, modifiedRow);
    console.log(newData);
    this.setState({
      data: newData,
    });
  }

  filterGroupToggle(index) {
    // Switch the groupFilter that was clicked to ON/OFF
    let newFilterGroups = this.state.filterGroups;
    newFilterGroups[index].on = !newFilterGroups[index].on;
    this.setState({
      filterGroups: newFilterGroups,
    });
    const included = this.state.filterGroups
      .filter((group) => {
        return group.on;
      })
      .map((group) => {
        return group.name;
      });
    if (included.length) {
      console.log(included);
      let newData = this.state.data;
      newData = newData.filter((row) => {
        return included.includes(row.group);
      });
      this.setState({
        data: newData,
      });
    } else {
      this.setState({
        data: this.state.originalData,
      });
    }
  }

  componentDidMount() {
    db.collection("inventoryData")
      .doc("filtering")
      .get()
      .then((doc) => {
        let newFilterGroups = [];
        doc.data().groups.map((group) => {
          newFilterGroups.push({
            name: group,
            on: false,
          });
          return this.setState({
            filterGroups: newFilterGroups,
          });
        });
      });
    db.collection("inventory")
      .get()
      .then((quertSnapshot) => {
        let data = [];
        quertSnapshot.forEach((doc) => {
          data.push({
            id: doc.id,
            ...doc.data(),
          });
        });
        this.setState({
          data,
          originalData: data,
        });
      });
  }

  render() {
    console.log("InventoryPage render");
    const { filterGroups } = this.state;
    return (
      <>
        <div className="container">
          <div className="h1 mb-4 mt-2">Inventory</div>
          {filterGroups.length ? (
            <div className="row justify-content-around">
              {filterGroups.map((group, index) => {
                return (
                  <div
                    key={index}
                    className={
                      "col-2 mx-1 mb-3 toggle-buttons " +
                      (group.on ? "ON" : null)
                    }
                    onClick={() => {
                      this.filterGroupToggle(index);
                    }}
                  >
                    {group.name}
                  </div>
                );
              })}
            </div>
          ) : (
            <div className="h4">Loading Filtering Groups...</div>
          )}
        </div>
        {this.state.data.length ? (
          <InventoryTable db={this.state.data} modalUpdate={this.modalUpdate} />
        ) : (
          <div className="container h4 mt-3">No items to show...</div>
        )}
      </>
    );
  }
}

export default InventoryPage;

表格组件:

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

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSortUp, faSortDown } from "@fortawesome/free-solid-svg-icons";

import { useTable, useSortBy, useGlobalFilter } from "react-table";

import ManualEditModal from "./ManualEditModal";
import GlobalFilter from "./GlobalFilter";

const InventoryTable = ({ db, modalUpdate }) => {
  const [modalData, setModalData] = useState(null);
  const [showModal, setShowModal] = useState(false);

  useEffect(() => {
    console.log("modal data effect");
    if (modalData) {
      setShowModal(true);
    } else {
      setShowModal(false);
    }
  }, [modalData]);

  const handleCloseModal = () => {
    console.log("close modal");
    // setShowModal(false);
    setModalData(null);
  };

  // i'm supposed to use useMemo here,
  // but i couldn't find a way to rerender the table
  // upon props change aside from deleting useMemo
  const data = React.useMemo(db, []);
  const columns = React.useMemo(
    () => [
      {
        Header: "Info",
        columns: [
          {
            Header: "Name",
            accessor: "name", // accessor is the "key" in the data
          },
          {
            Header: "Type",
            accessor: "type",
          },
        ],
      },
      {
        Header: "Stock",
        columns: [
          {
            Header: "Current Stock",
            accessor: "stock",
          },
          {
            Header: "Awaiting Arrival",
            accessor: "await_arrival",
          },
          {
            Header: "Awaiting Order",
            accessor: "await_order",
          },
        ],
      },
    ],
    []
  );

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,
    setGlobalFilter,
  } = useTable({ columns, data }, useGlobalFilter, useSortBy);
  const { globalFilter } = state;

  return (
    <div className="container mt-3">
      {showModal ? (
        <div className="editRowModal">
          <ManualEditModal
            show={showModal}
            data={modalData}
            onHide={handleCloseModal}
            modalUpdate={modalUpdate}
          />
        </div>
      ) : null}

      <div className="form-group mb-3">
        <GlobalFilter filter={globalFilter} setFilter={setGlobalFilter} />
      </div>
      <table {...getTableProps()} className="table table-bordered">
        <thead className="thead-dark">
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th
                  {...column.getHeaderProps(column.getSortByToggleProps())}
                  scope="col"
                >
                  {column.render("Header")}
                  <span className="sorting-icon">
                    {column.isSorted ? (
                      column.isSortedDesc ? (
                        <FontAwesomeIcon icon={faSortUp} className="ml-2" />
                      ) : (
                        <FontAwesomeIcon icon={faSortDown} className="ml-2" />
                      )
                    ) : (
                      ""
                    )}
                  </span>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row) => {
            prepareRow(row);
            return (
              <tr
                {...row.getRowProps()}
                onClick={() => {
                  setModalData(row.original);
                }}
              >
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default InventoryTable;

模态组件:

import React, { useState } from "react";
import { Modal, Button } from "react-bootstrap";
import { db } from "../../../firebase/firebase";

const ManualEditModal = ({ show, data, onHide, modalUpdate }) => {
  const [stock, setStock] = useState(data ? data.stock : -1);

  // update the database on the new stock value
  const onSave = () => {
    if (isNaN(Number(stock)) || stock < 0) {
      alert("Invalid value");
      return;
    }
    db.collection("inventory")
      .doc(data.id)
      .update({
        stock: Number(stock),
      })
      .then(() => {
        // call a function to update the state (and therefore the table) on the new values.
        data.stock = Number(stock);
        modalUpdate(data);
        onHide();
      });
  };

  if (show && data) {
    return (
      <Modal show={show} onHide={onSave}>
        <Modal.Header closeButton>
          <Modal.Title>{data.name}</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className="input-group">
            <div className="input-group-prepend">
              <span className="input-group-text">Current Stock</span>
            </div>
            <input
              className="form-control"
              type="number"
              value={stock}
              onChange={(e) => {
                setStock(e.target.value);
              }}
            />
          </div>
        </Modal.Body>
        <Modal.Footer>
          <Button variant="primary" onClick={onSave}>
            Save & Close
          </Button>
          <Button variant="secondary" onClick={onHide}>
            Close
          </Button>
        </Modal.Footer>
      </Modal>
    );
  } else {
    return null;
  }
};
export default ManualEditModal;

提前感谢您的帮助,我希望这可以完成......在这个问题上 2 周!

更新:截至目前,我尝试过(没有成功):

  1. 将 useMemo 钩子从数据常量中删除到表中,使其更频繁地重新呈现,但似乎并没有削减它。
  2. 将 props 中的数据作为新数组传递,并将旧数组传播到其中。
4

0 回答 0