1
function Inhook(props) {
  const initialState = 0;
  const [records, setRecords] = useState([]);
  const [count, setCount] = useState(initialState);
  const [show, setShow] = useState(false);
  const [store, setStore] = useState(initialState);
  const [store1, setStore1] = useState(initialState);
  setRecords(props.records);

  function val(e) {
    debugger;
    console.log("hhh", e);
    setStore(e);
    if (store === store1) {
      if (count == 0) {
        setShow(true);
      } else {
        setShow(false);
      }
    } else {
      setShow(true);
      setCount(0);
    }
    setCount(count + 1);
    // console.log(count,'counttt');

    setStore1(e);
  }
  return (
    <div>
      <React.Fragment>
        <br />
        <div className="Tree">
          <h1 style={{ textAlign: "center" }}>Employee Tree</h1>
          <h3>Test Case 1</h3>
          <h4>Employee Tree</h4>
          {
            (records.sort((x, y) => (x.empName.toLowerCase() > y.empName.toLowerCase()) * 2 - 1),
            records.map(empId => {
              return empId.managerId === 0 ? (
                <ul key={empId.id}>
                  <li style={{ fontWeight: "Bold" }}>
                    {empId.empName.toLowerCase()}
                    <p>Employees of : {empId.empName.toLowerCase()}</p>
                    <ul>
                      {records.map(s =>
                        s.managerId === empId.id ? (
                          <li type="square" key={s.id}>
                            {s.empName.toLowerCase()}
                            {empId.managerId === s.id ? <p>Employees of :{s.empName.toLowerCase()}</p> : <p></p>}
                            {records.map(e =>
                              e.managerId === s.id ? (
                                <div>
                                  {e.managerId === s.id ? <p>{val(s.id)}</p> : <p></p>}
                                  {show ? <p>Employees of :{s.empName.toLowerCase()}</p> : <p></p>}
                                  <li key={e.id} type="disc" style={{ marginLeft: "120px" }}>
                                    {e.empName.toLowerCase()}
                                  </li>
                                </div>
                              ) : (
                                ""
                              )
                            )}
                          </li>
                        ) : (
                          ""
                        )
                      )}
                    </ul>
                  </li>
                </ul>
              ) : (
                ""
              );
            }))
          }
        </div>
      </React.Fragment>
    </div>
  );
}
export default Inhook;

I got data of records from json which it has name, id , managerId and salary and so on. when i did in class component it worked got the output ,in the function or hooks the val() function in the jsx calling infinity times got the error like (Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.)

Utsav Patel
  • 2,789
  • 1
  • 16
  • 26
C09-G
  • 21
  • 4

2 Answers2

0

You are changing the state inside the render by calling val(s.id) in the case that e.managerId === s.id is true. Then, when they are equal and while the component is trying to render val(s.id) changes a bunch of state in its function body (val(e)) and the component starts to render again ad infinitum.

Try and see if you can separate concerns in val(e) by bringing some setters out, maybe a separate function for each. Also, calculate the value of what you want to display inside the "true" p-tag (in place of <p> {val(s.id)}</p>) outside the render and then just pass it to jsx!

rtviii
  • 807
  • 8
  • 19
0

You need to remove this line setRecords(props.records) because it causes the state to change on every render, which is the infinite loop you have.
Moreover, you don't need this line also const [records, setRecords] = useState([]); and you can just display the records you have in the props, no need for local state here.

Moreover, some advices:

  • It seems you are trying to build and display a tree of employees in the same time, which is very difficult, you should build the data that you need to display before you display it. To build a tree from an array, check out this stackoverflow answer

It would look like this :


function Inhook(props) {
    const initialState = 0;
    const records = props.records

    const sortedRecords = records.sort((x, y) => (x.empName.toLowerCase() > y.empName.toLowerCase()) * 2 - 1)
    const employeeTree = createEmployeeTree(sortedRecords)

    return (
        <div>
            <React.Fragment>
                <br />
                <div className="Tree">
                    <h1 style={{ textAlign: 'center' }}>Employee Tree</h1>
                    <h3>Test Case 1</h3>
                    <h4>Employee Tree</h4>
                    {employeeTree.map(manager => {
                        return (
                            <ul key={manager.id}>
                                <li style={{ fontWeight: 'bold' }}>
                                    <p>
                                        Employees of :
                                        {manager.empName.toLowerCase()}
                                    </p>
                                    <ul>
                                        {manager.children.map(employee => (
                                            <li type="square" key={employee.id}>
                                                {employee.empName.toLowerCase()}
                                                {employee.children.map(e => (
                                                    <div>
                                                        <li
                                                            key={e.id}
                                                            type="disc"
                                                            style={{
                                                                marginLeft:
                                                                    '120px',
                                                            }}>
                                                            {e.empName.toLowerCase()}
                                                        </li>
                                                    </div>
                                                ))}
                                            </li>
                                        ))}
                                    </ul>
                                </li>
                            </ul>
                        );
                    })}
                </div>
            </React.Fragment>
        </div>
    );
}

  // Convert flat array to tree, see https://stackoverflow.com/a/40732240/6695569
    const createEmployeeTree = data => {
        let hashTable = {};
        data.forEach(
            aData => (hashTable[aData.id] = { ...aData, children: [] })
        );
        let dataTree = [];
        data.forEach(aData => {
            if (aData.managerId) {
                if (!hashTable[aData.managerId]) return;
                hashTable[aData.managerId].children.push(hashTable[aData.id]);
            } else dataTree.push(hashTable[aData.id]);
        });
        return dataTree;
    };

  • Another advice, don't use local state for derived values, for example your show state was set to true when count was more than 0. Then you should just use a calculated value const show = count >0 :
// instead of this

const [count, setCount] = useState(initialState);
const [show, setShow] = useState(false);
function(){
  setCount(0)
  setShow(false)
  ...
  if(count > 0) setShow(true)
  else setShow(false)
}

//do This

const [count, setCount] = useState(initialState);
const show = count > 0
  • Another advice, JSX is very easy to split into components, so do it and don't make very long renders that can be very difficult to read, you can split it like this :
function Inhook(props) {
return (
<div>
  <Title />
  <Managers employeeTree={employeeTree} />
</div>
)
}

function Title(){
   return <h1 style={{ textAlign: 'center' }}>Employee Tree</h1>
}


function Managers({ employeeTree }) {
    return (
        <ul>
            {employeeTree.map(manager => (
                <li style={{ fontWeight: 'bold' }}>
                    <p>Employees of :{manager.empName.toLowerCase()}</p>

                    <Employees employees={manager.children} />
                </li>
            ))}
        </ul>
    );
}

function Employees({ employees }) {
    return (
        <ul>
            {employees.map(employee => (
                <li type="square" key={employee.id}>
                    {employee.empName.toLowerCase()}
                    {employee.children.map(e => (
                        <div>
                            <li
                                key={e.id}
                                type="disc"
                                style={{
                                    marginLeft: '120px',
                                }}>
                                {e.empName.toLowerCase()}
                            </li>
                        </div>
                    ))}
                </li>
            ))}
        </ul>
    );
}

Stephane L
  • 2,879
  • 1
  • 34
  • 44