React can't perform state update on unmounted component - checking isMounted not fixing

Viewed 38

I am using axios to return data from an API and trying to present this in to various nested components in my React App.

The code looks something like this:

const Building = () => {
  const { bid } = useParams();
  const { userAccessToken } = useAuth();
  const [buildingData, setBuildingData] = useState([]);
  const bearerToken = `Bearer ${userAccessToken}`;
  React.useEffect(() => {
    let isMounted = true;
    const axiosConfig = {
      headers: { Authorization: bearerToken },
    };
    axios
      .get(
        "http://localhost:3001/building?requestedlid=2&requestedbid=" + bid,
        axiosConfig
      )
      .then(function (response) {
        if (isMounted) {
          setBuildingData(response.data[0]);
        }
      })
      .catch(function (error) {
        // handle error
        console.log(error);
      });
    return () => {
      isMounted = false;
    };
  }, [bearerToken, bid]);

  return (
    <React.Fragment>
      <Helmet title="Building Profile" />
      <Container fluid className="p-0">
        <Breadcrumb className="float-end mt-2">
          <Breadcrumb.Item href="/dashboard/default">Home</Breadcrumb.Item>
          <Breadcrumb.Item href="/buildings/portfolio">
            Portfolio
          </Breadcrumb.Item>
          <Breadcrumb.Item active>Building Profile</Breadcrumb.Item>
        </Breadcrumb>
        <h1 className="h3 mb-3">
          Building Profile
          <OffcanvasHelp
            id="buildingprofile"
            name="Building Profile"
            scroll
            backdrop
          />
        </h1>
        <div className="clearfix"></div>
        <Row>
          <Col xl="8">
            <BuildingProfile
              name={buildingData.building_name}
              status={buildingData.status}
              description={buildingData.description}
              keycontacts={buildingData.key_contacts}
              created={buildingData.stats.created_date}
              golive={buildingData.stats.golive_date}
            />
            <Rooms />
          </Col>
          <Col xl="4">
            <AccountManager />
            <Map location={buildingData.location} />
            <GetSupport type="commercial" />
          </Col>
        </Row>
      </Container>
    </React.Fragment>
  );
};

My problem is I am receiving the common error:

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

Using the methods described in many StackOverflow answers, to check an isMounted boolean as in my code above, I am unable to resolve the issue.

Weirdly, the issue specifically occurs when I am passing these two props to the BuildingProfile component:

created={buildingData.stats.created_date}
golive={buildingData.stats.golive_date}

If I don't pass these two props, everything else works fine.

I'm sure I'm missing something silly but after several hours of trying to figure it out I'm still stuck. Anybody who can provide a pointer or any tips, I would be really grateful.

Many thanks

--- Update - including the BuildingProfile component:

const BuildingProfile = ({
  name,
  status,
  description,
  created,
  golive,
  keycontacts,
}) => {
  // Modal config for "Deactivate Building"
  const initOpenModals = () => {
    let modals = {};
    colors.forEach((color, index) => {
      modals = Object.assign({}, modals, { [index]: false });
    });
    console.log(modals);
    return modals;
  };

  const [openModals, setOpenModals] = useState(() => initOpenModals());

  const toggle = (index) => {
    // Toggle selected element
    setOpenModals((openModals) =>
      Object.assign({}, openModals, { [index]: !openModals[index] })
    );
  };

  const notyf = useContext(NotyfContext);
  const [type] = useState("success");
  const [duration] = useState("5000");
  const [ripple] = useState(true);
  const [dismissible] = useState(false);
  const [positionX] = useState("right");
  const [positionY] = useState("top");

  const navigate = useNavigate();

  return (
    <Card>
      <Card.Header className="mb-0 pb-0">
        <Card.Title className="mb-0">
          <IsAllowed to="edit:buildings">
            <div className="card-actions float-end">
              <Dropdown align="end">
                <Dropdown.Toggle as="a" bsPrefix="-">
                  <MoreHorizontal />
                </Dropdown.Toggle>
                <Dropdown.Menu>
                  <Dropdown.Item onClick={() => navigate("/buildings/edit")}>
                    Edit Building
                  </Dropdown.Item>
                  <React.Fragment key="deactivateBuilding">
                    <Dropdown.Item onClick={() => toggle("deactivateBuilding")}>
                      Deactivate Building
                    </Dropdown.Item>
                    <Modal
                      show={openModals["deactivateBuilding"]}
                      onHide={() => toggle("deactivateBuilding")}
                      centered
                    >
                      <Modal.Header closeButton>
                        <b>Admin Function:</b>&nbsp; Deactivate Building
                      </Modal.Header>
                      <Modal.Body className="m-3">
                        <p className="text-left mb-0">
                          Are you sure you want to deactivate the
                          <b>Bus Works</b> building? This will prevent the
                          building from showing up in the platform completely.
                        </p>
                      </Modal.Body>
                      <Modal.Footer>
                        <Button
                          variant="secondary"
                          onClick={() => toggle("deactivateBuilding")}
                        >
                          Close
                        </Button>{" "}
                        <Button
                          variant="danger"
                          onClick={() => {
                            toggle("deactivateBuilding");
                            notyf.open({
                              type,
                              message: "The building has been deactivated.",
                              duration,
                              ripple,
                              dismissible,
                              position: {
                                x: positionX,
                                y: positionY,
                              },
                            });
                          }}
                        >
                          Deactivate Building
                        </Button>
                      </Modal.Footer>
                    </Modal>
                  </React.Fragment>
                </Dropdown.Menu>
              </Dropdown>
            </div>
          </IsAllowed>
          <h1 className="mb-0 pb-0">{name}</h1>
          <Badge
            className={
              status === "Live Building"
                ? "my-2 btn-gradient inline"
                : "my-2 inline"
            }
            bg="success"
          >
            {status}
          </Badge>
        </Card.Title>
      </Card.Header>
      <Card.Body>
        <h5>Building Overview:</h5>
        <p className="mb-4">{description}</p>
        <div className="row">
          <div className="col-md-4">
            <div className="mb-4">
              <h5>Created Date</h5>
              <p>{created}</p>
            </div>
          </div>
          <div className="col-md-4">
            <div className="mb-4">
              <h5>Go-Live Date</h5>
              <p>{golive}</p>
            </div>
          </div>
          <div className="col-md-4">
            <div className="mb-4">
              <h5>Key Contacts</h5>
              <div>
                <span className="me-1">
                  <OverlayTrigger
                    placement="right"
                    overlay={
                      <Tooltip id="tooltip-right">Joe Bloggs</Tooltip>
                    }
                  >
                    <img
                      src={avatar3}
                      width="28"
                      height="28"
                      className="rounded-circle me-2"
                      alt="Joe Bloggs"
                    />
                  </OverlayTrigger>
                </span>
                <span className="me-1">
                  <OverlayTrigger
                    placement="right"
                    overlay={
                      <Tooltip id="tooltip-right">Joe Bloggs</Tooltip>
                    }
                  >
                    <img
                      src={avatar2}
                      width="28"
                      height="28"
                      className="rounded-circle me-2"
                      alt="Joe Bloggs"
                    />
                  </OverlayTrigger>
                </span>
                <span className="me-1">
                  <OverlayTrigger
                    placement="right"
                    overlay={
                      <Tooltip id="tooltip-right">Joe Bloggs</Tooltip>
                    }
                  >
                    <img
                      src={avatar1}
                      width="28"
                      height="28"
                      className="rounded-circle me-2"
                      alt="Joe Bloggs"
                    />
                  </OverlayTrigger>
                </span>
                <Link to="#" className="d-inline-block text-muted fw-bold ms-2">
                  +2 more
                </Link>
              </div>
            </div>
          </div>
        </div>
      </Card.Body>
    </Card>
  );
};
0 Answers
Related