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;