React Components are re-rendering Infinite times

All most all components in the router file runs infinitely. Don’t know what’s the problem. The ajax request sends infinite GET requests due to this issue.

All the files look like something similar to this.

import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { apiCall } from "../handlers/api";
import BasicTable from "../reusable/table";
import { loadFields } from "../store/actions/actionCreators";

const header = [
  "Sl.No",
  "Item Code",
  "Item Name",
  "Item Type",
  "UoM",
  "HSN CODE",
  "Specifications",
  "Description",
  "Brand",
  "Price",
];

function Item(props) {
  const [fields, setFields] = useState([]);
  const [render, setRender] = useState(0);
  console.log(fields);

  // useEffect(() => {
  //   props
  //     .loadFields("/items", 0, 20)
  //     .then((res) => {
  //       console.log(res);
  //     })
  //     .catch((err) => console.log(err));
  //   // eslint-disable-next-line react-hooks/exhaustive-deps
  // }, []);
  apiCall("get", "/product", {})
    .then((data) => setFields(data.product))
    .catch((err) => console.log(err));

  const reRender = () => {
    setRender(render + 1);
  };

  return (
    <div>
      <h1>Items</h1>
      <BasicTable reRender={reRender} header={header} body={fields} />
    </div>
  );
}

const mapStateToProps = (state) => ({
  item: state.Items.fields,
});

export default connect(mapStateToProps, { loadFields })(Item);

Routes file: Here, all the routes are defined.

import React from "react";
import { Route, BrowserRouter as Router, Switch } from "react-router-dom";
import Home from "./home";
import Supplier from "./supplier";
import Item from "./item";
import Menubar from "./menubar";
import Project from "./project";
import Fields from "./fields";
import User from "./user";
import GeneratePO from "./generatePo";
import PODetails from "./poDetails";
import AddButton from "./addButton";
import AddFields from "./addFields";
import { connect } from "react-redux";
import ViewItems from "../reusable/viewItems";
import AddMaterialForm from "../reusable/addMaterialForm";
import ViewMaterialFormItem from "../reusable/viewMaterialFormItem";
import InventoryHeader from "./inventoryHeader";
import InventoryDetails from "./inventoryDetails";
import AddIntentTable from "../reusable/addIntentTable";
import InventoryIssues from "./inventoryIssues";
import InventoryIndents from "./inventoryIndents";
import ItemForm from "../reusable/itemForm";
import POReport from "../reports/poReport";

function Routers(props) {
  return (
    <React.Fragment>
      <Router>
        <header className="width-max navbar">
          <Menubar />
          <AddButton />
        </header>
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route exact path="/users">
            <User />
          </Route>
          <Route exact path="/items">
            <Item />
          </Route>
          <Route exact path="/suppliers">
            <Supplier />
          </Route>
          <Route exact path="/fields">
            <Fields />
          </Route>
          <Route exact path="/projects">
            <Project />
          </Route>
          <Route exact path="/generatepo">
            <GeneratePO />
          </Route>
          <Route exact path="/inventoryheader">
            <InventoryHeader />
          </Route>
          <Route exact path="/inventorydetails">
            <InventoryDetails />
          </Route>
          <Route path="/items/add">
            <ItemForm type="POST" />
          </Route>
          <Route path="/users/add">
            <AddFields field="/users" data={{}} type="POST" />
          </Route>
          <Route path="/suppliers/add">
            <AddFields field="/suppliers" data={{}} type="POST" />
          </Route>
          <Route path="/fields/add">
            <AddFields field="/fields" data={{}} type="POST" />
          </Route>
          <Route path="/projects/add">
            <AddFields field="/projects" data={{}} type="POST" />
          </Route>
          <Route path="/generatepo/add">
            <AddMaterialForm field="/generatepo" data={{}} type="POST" />
          </Route>
          <Route path="/inventoryheader/add">
            <AddIntentTable field="/inventoryheader" data={{}} type="POST" />
          </Route>
          <Route path="/items/edit/:ID">
            <ItemForm type="PUT" />
          </Route>
          <Route path="/users/edit/:ID">
            <AddFields field="/users" data={props.user} type="PUT" />
          </Route>
          <Route path="/suppliers/edit/:ID">
            <AddFields field="/suppliers" data={props.supplier} type="PUT" />
          </Route>
          <Route path="/fields/edit/:ID">
            <AddFields field="/fields" data={props.field} type="PUT" />
          </Route>
          <Route path="/projects/edit/:ID">
            <AddFields field="/projects" data={props.project} type="PUT" />
          </Route>
          <Route exact path="/inventory/edit">
            <InventoryHeader />
          </Route>
          <Route path="/purchase/edit">
            <GeneratePO />
          </Route>
          <Route path="/generatepo/edit/:ID">
            <AddMaterialForm
              field="/generatepo"
              data={props.materialForm}
              type="PUT"
            />
          </Route>
          <Route path="/inventoryheader/edit/:ID">
            <AddIntentTable
              field="/inventoryheader"
              data={props.inventoryTable}
              type="PUT"
            />
          </Route>
          <Route path="/items/view/:ID">
            <ViewItems field="/items" data={props.item} />
          </Route>
          <Route path="/users/view/:ID">
            <ViewItems field="/users" data={props.user} />
          </Route>
          <Route path="/suppliers/view/:ID">
            <ViewItems field="/suppliers" data={props.supplier} />
          </Route>
          <Route path="/fields/view/:ID">
            <ViewItems field="/fields" data={props.field} />
          </Route>
          <Route path="/projects/view/:ID">
            <ViewItems field="/projects" data={props.project} />
          </Route>
          <Route path="/generatepo/view/:ID">
            <ViewMaterialFormItem
              field="/generatepo"
              data={props.materialForm}
            />
          </Route>
          <Route path="/inventoryheader/view/:ID">
            <ViewItems field="/inventoryheader" data={props.inventoryTable} />
          </Route>
          <Route path="/inventoryissues">
            <InventoryIssues />
          </Route>
          <Route path="/inventoryindents">
            <InventoryIndents />
          </Route>
          <Route path="/podetails">
            <PODetails />
          </Route>
          <Route path="/poreport">
            <POReport />
          </Route>
        </Switch>
      </Router>
    </React.Fragment>
  );
}

const mapStateToProps = (state) => ({
  item: state.Items.fields,
  field: state.Fields.fields,
  project: state.Projects.fields,
  supplier: state.Suppliers.fields,
  user: state.Users.fields,
  materialForm: state.MaterialForm.fields,
  inventoryTable: state.InventoryTable.fields,
});

export default connect(mapStateToProps, null)(Routers);

table.js file: This is a reusable component that most of the files use dynamicly.

import React, { useState, useEffect } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import VisibilityIcon from "@material-ui/icons/Visibility";
import EditIcon from "@material-ui/icons/Edit";
import DeleteIcon from "@material-ui/icons/Delete";
import { BottomScrollListener } from "react-bottom-scroll-listener";
import { connect } from "react-redux";
import { loadFields, removeFields } from "../store/actions/actionCreators";
import { useLocation, useHistory } from "react-router-dom";

const useStyles = makeStyles({
  table: {
    minWidth: 650,
  },
});

function BasicTable(props) {
  const location = useLocation();
  const history = useHistory();
  const [items, setItems] = useState([...props.body]);
  const [limit, setLimit] = useState(20);
  const classes = useStyles();

  useEffect(() => {
    const interval = setInterval(() => setItems([...props.body]), 500);
    return () => {
      clearInterval(interval);
    };
  }, [limit, props.body]);

  const handleDelete = (data) => {
    props.removeFields(location.pathname, data);
    setItems(items.filter((item) => item.id !== data.id));
    props.reRender();
  };

  const handleEdit = (id) => {
    history.push(`${location.pathname}/edit/${id}`);
  };

  const handleView = (id) => {
    history.push(`${location.pathname}/view/${id}`);
  };

  const handleScroll = () => {
    // setItems([
    //   ...items,
    //   ...props.body.slice(
    //     limit,
    //     props.body.length > limit + 20 ? limit + 20 : props.body.length
    //   ),
    // ]);
    // setLimit(limit + 20);
  };
  const tableHeader = props.header.map((item, index) => {
    if (index === 0) {
      return (
        <TableCell key={item}>
          <b>{item}</b>
        </TableCell>
      );
    } else {
      return (
        <TableCell key={item} align="right">
          <b>{item}</b>
        </TableCell>
      );
    }
  });

  const tableContent = items.map((item, index) => {
    return (
      <TableRow key={index}>
        {Object.values(item).map((row, ind) =>
          ind === 0 ? (
            <TableCell key={ind} component="th" scope="row">
              {row}
            </TableCell>
          ) : typeof row === "object" ? (
            String(row.name ? row.name : null)
          ) : (
            <TableCell key={ind} align="right">
              {location.pathname === "/users" && ind === 3 ? "**********" : row}
            </TableCell>
          )
        )}
        {location.pathname === "/inventoryindents" ? (
          <Button variant="outlined" color="primary">
            Open Indent
          </Button>
        ) : (
          <TableCell align="right">
            {/* <VisibilityIcon
              style={{ margin: "5px", cursor: "pointer" }}
              onClick={() => handleView(item.id)}
            /> */}
            <EditIcon
              onClick={() => handleEdit(item.id)}
              style={{ margin: "5px", cursor: "pointer" }}
            />
            <DeleteIcon
              onClick={() => handleDelete(item)}
              style={{ margin: "5px", cursor: "pointer" }}
            />
          </TableCell>
        )}
      </TableRow>
    );
  });

  return (
    <BottomScrollListener onBottom={() => handleScroll()}>
      <TableContainer component={Paper}>
        <Table className={classes.table} aria-label="simple table">
          <TableHead>
            <TableRow>
              {tableHeader}
              <TableCell align="right">
                <b>Actions</b>
              </TableCell>
            </TableRow>
          </TableHead>
          <TableBody>{tableContent}</TableBody>
        </Table>
      </TableContainer>
      <br />
      <br />
      <br />
    </BottomScrollListener>
  );
}

const mapStateToProps = (state) => ({
  state,
});

export default connect(mapStateToProps, { loadFields, removeFields })(
  BasicTable
);

please help

Answer

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, causes all the User Interface (UI) elements to be re-rendered automatically. In your first file, you are making some API call which on success changing the state. Which will tell the react to re-render the component, and again it will do the API and it goes on.

Do all the side effects like API call in useEffect function with proper dependency array.

Leave a Reply

Your email address will not be published. Required fields are marked *