Home > front end >  Too many re-renders useState React js
Too many re-renders useState React js

Time:01-22

I want to display objects from the array one by one by clicking on the card.

To do this, I made a check for array length (props.tasks.length), and if it is more than 1, then the array is shuffled and then I want to display these objects one by one on click.

But after a click, a new array is generated each time and often the objects are repeated 2-4 times.

But I get an error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

function App(props) {
  let [random, setRandom] = useState({});
  let [newArr, setNewArr] = useState(props.tasks.sort(() => Math.random() - 0.5));
  let i = 0;
  random = newArr[i]
  setRandom(newArr[i])

  const randomCard =()=> {
    console.log(random);
    console.log(i); 
    console.log(newArr[0],newArr[1],newArr[2],newArr[3], newArr[4], newArr[5]);
    console.log(newArr[i]); 
    if (i <= newArr.length) {
      i  
    } else {
      newArr = props.tasks.sort(() => Math.random() - 0.5);
      console.log('clean');
      i=0
    }
  }

  return (
    <div>
      {newArr.length > 1 ? (
        <div className="item" onClick={randomCard}>
          <p>{random.name}</p>
          <p>{random.translate}</p>
          <p>{random.note}</p>
        </div>
      ) : (
        <p>Nothing</p>
      )}
    </div>
  );
}

export default App;

CodePudding user response:

The main culprit in your code example is

setRandom(newArr[i])

Using a hook's set method should only be done via an action or wrapped in a useEffect for side effects. In your code, setNewArr is called on every rerender and will cause the component to rerender... causing the infinite loop of rerenders.

You also don't need to store the selected element from your array in a state, you're essentially doing this by just storying the index in the use state.

Your solution should look something like this.

Also you want to reset i when it's < newArr and not <= newArr because if your array is of length "2" and i is "2" then you're setting i to "3" which doesn't point to any element in your list.

const shuffle = (arr) => arr.sort(() => Math.random() - 0.5);

function App(props) {

  // Default empty list
  const [newArr, setNewArr] = useState([]);

  // Sets the default index to 0
  const [i, setI] = useState(0);

  // We don't want to call shuffle on every rerender, so only setNewArr
  // Once when the component is mounted.
  useEffect(() => {
   setNewArr(shuffle(props.tasks));
  }, []);

  const randomCard =()=> {
    if (i < newArr.length) {
      setI(i   1);
    } else {
      setNewArr(shuffle(props.tasks));
      setI(0);
    }
  }

  return (
    <div>
      {newArr.length > 1 ? (
        <div className="item" onClick={randomCard}>
          <p>{newArr[i].name}</p>
          <p>{newArr[i].translate}</p>
          <p>{newArr[i].note}</p>
        </div>
      ) : (
        <p>Nothing</p>
      )}
    </div>
  );
}

export default App;
  • Related