React Hook React.useCallback has missing dependencies

I am using react table 7 with subcomponents. I've built my table using the example provided in the React Table 7 API examples. However, I get a warning,

React Hook React.useCallback has missing dependencies: 'props.setStatus' and 'statusColumns'. Either include them or remove the dependency array

The dependencies are stated as variables before the return statement, but within the function. The column names are recognized and implemented correctly, so why am I getting this warning and how can I prevent this?

Here is the code implementation:

const EnforcementActionsTable = (props) => {
  const columns = [
    {
      Header: () => null, // No header
      id: "expander", // It needs an ID
      width: 30,
      Cell: ({ row }) => (
        <span {...row.getToggleRowExpandedProps()}>
          {row.isExpanded ? (
            <FontAwesomeIcon className="font-icon" icon={faCaretDown} />
          ) : (
            <FontAwesomeIcon className="font-icon" icon={faCaretRight} />
          )}
        </span>
      )
    },
    {
      Header: "Edit Action",
      id: "eaId",
      Cell: (row) => {
        return (
          <div className="text-center">
            <FontAwesomeIcon
              className="font-icon"
              icon={faEdit}
              onClick={() => {
                props.handleShow(props.id);
                props.setItem(row.original);
              }}
            />
          </div>
        );
      },
      width: 75,
      disableFilters: true
    },
    {
      Header: "Add Status",
      id: "eaStatus",
      Cell: (row) => {
        return (
          <div className="text-center">
            <FontAwesomeIcon
              className="font-icon"
              style={{ color: "green" }}
              icon={faPlusCircle}
              onClick={() => {
                props.handleShow(props.statusModalId);
                props.setItem(row.original);
              }}
            />
          </div>
        );
      },
      width: 75,
      disableFilters: true
    },
    {
      Header: "EA Code",
      accessor: "eaCode",
      width: 100
    },
    {
      Header: "Assigned To",
      accessor: "assignedTo"
    },
    {
      Header: "Date Intiated",
      id: "dateInitiated",
      accessor: (d) => {
        return d.dateInitiated ? formatDateMDY(d.dateInitiated) : "";
      },
      width: 135
    },
    {
      Header: "Due Date Req.",
      id: "dueDateRequired",
      accessor: (d) => {
        return d.dueDateRequired ? "Yes" : "No";
      },
      width: 135
    },
    {
      Header: "Due Date",
      id: "dueDate",
      accessor: (d) => {
        return d.dueDate ? formatDateMDY(d.dueDate) : "";
      },
      width: 100
    },
    {
      Header: "Date Completed",
      id: "dateComplete",
      accessor: (d) => {
        return d.dateComplete ? formatDateMDY(d.dateComplete) : "";
      }
    },
    {
      Header: "Days Past",
      id: "daysPassed",
      accessor: (d) => {
        return d.daysPassed ? <span className={d.daysPassed < 0 ? "error" : ""}>{d.daysPassed}</span> : "";
      }
    }
  ];

  const statusColumns = [
    {
      Header: "Edit Status",
      id: "eaId",
      Cell: (row) => {
        return (
          <div className="text-center">
            <FontAwesomeIcon
              className="font-icon"
              icon={faEdit}
              onClick={() => {
                props.handleShow(props.statusModalId);
                props.setStatus(row.original);
              }}
            />
          </div>
        );
      },
      width: 75,
      disableFilters: true
    },
    {
      Header: "",
      id: "viewComplianceSchedule",
      accessor: (d) => {
        return d.status === "Compliance" ? (
          <span
            style={{ textDecoration: "underline", color: "#5fa7be", cursor: "pointer" }}
            onClick={() => {
              props.handleShow(props.complianceModalId);
              props.handleShowComplianceSchedule(d.tenschdIsNumber);
            }}
          >
            <FontAwesomeIcon className="font-icon" icon={faEye} />
          </span>
        ) : (
          ""
        );
      },
      disableFilters: true,
      width: 65
    },
    {
      Header: "Status",
      accessor: "status"
    },
    {
      Header: "Initial Date",
      id: "dateInitiated",
      accessor: (d) => {
        return d.dateInitiated ? formatDateMDY(d.dateInitiated) : "";
      }
    },
    {
      Header: "Response Required",
      id: "responseRequired",
      accessor: (d) => {
        return d.responseRequired ? "Yes" : "No";
      }
    },
    {
      Header: "Response Due",
      id: "responseDue",
      accessor: (d) => {
        return d.responseDue ? (
          <span className={d.responseDue < new Date() ? "error" : ""}>{formatDateMDY(d.responseDue)}</span>
        ) : (
          ""
        );
      }
    },
    {
      Header: "Response Received",
      id: "responseReceived",
      accessor: (d) => {
        return d.responseReceived ? formatDateMDY(d.responseReceived) : "";
      }
    },
    {
      Header: "Staff Assigned",
      accessor: "assignedStaff"
    },
    {
      Header: "Date Completed",
      id: "statusComplete",
      accessor: (d) => {
        return d.statusComplete ? formatDateMDY(d.statusComplete) : "";
      }
    },
    {
      Header: "Comments",
      accessor: "responseComments",
      width: 200
    }
  ];

  return (
    <React.Fragment>
      <Row>
        <Col>
          <EnforcementStatusModal item={props.item} {...props} />
        </Col>
        <Col>
          <EnforcementActionModal item={props.item} {...props} />
        </Col>
      </Row>
      <Col>
        <ComplianceScheduleModal {...props} />
      </Col>
      <Row>
        <Col>
          <Table
            columns={columns}
            data={props.data}
            rowOnClick={true}
            rowClickHandler={props.setItem}
            renderRowSubComponent={React.useCallback(
              ({ row }) =>
                row.original.enforcementActionStatusList.length > 0 ? (
                  <Table
                    data={row.original.enforcementActionStatusList}
                    columns={statusColumns}
                    rowOnClick={true}
                    rowClickHandler={props.setStatus}
                  />
                ) : (
                  "No data"
                ),
              []
            )}
          />
        </Col>
      </Row>
    </React.Fragment>
  );
};

export default EnforcementActionsTable;

Upvotes: 0

Views: 968

Answers (1)

Maddy Blacklisted
Maddy Blacklisted

Reputation: 1190

Add props.setStatus and statusColumns to the dependency array.

renderRowSubComponent={React.useCallback(
          ({ row }) =>
            row.original.enforcementActionStatusList.length > 0 ? (
              <Table
                data={row.original.enforcementActionStatusList}
                columns={statusColumns}
                rowOnClick={true}
                rowClickHandler={props.setStatus}
              />
            ) : (
              "No data"
            ),
          [statusColumns,props.setStatus]
        )}

As per the hooks documentation

useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

Upvotes: 1

Related Questions