I want to increment the number of users after each 200ms till 5000 with the below code. But it doesn't clear the interval when the number of users greater than 5000.
const Cards = () => {
const [users, setUsers] = useState(40);
useEffect(() => {
const setIntervalUsers = setInterval(() => {
setUsers((prevUsers) => prevUsers = prevUsers 100)
}, 200);
if (users >= 5000) {
console.log('ok');
clearInterval(setIntervalUsers)
}
}, []);
return (<div>number of users {users} </div>)}
CodePudding user response:
I would suggest you to return a clean up function so you don't register the interval twice in case you are in StrictMode
with React 18, and also to remove it from the memory when the component gets unmounted.
Also use a ref
sets with useRef
and a separate useEffect
that would watch changes in users
and clear the interval there. Like so:
import { useEffect, useRef, useState } from "react";
const Cards = () => {
const [users, setUsers] = useState(40);
const intervalRef = useRef();
useEffect(() => {
if (users >= 5000) {
console.log("ok");
clearInterval(intervalRef.current);
}
}, [users]);
useEffect(() => {
intervalRef.current = setInterval(() => {
setUsers((prevUsers) => (prevUsers = prevUsers 100));
}, 200);
return () => clearInterval(intervalRef.current);
}, []);
return <div>number of users {users} </div>;
};
CodePudding user response:
This doesnt work because:
- you never call the useEffect again to check if the condition is met
- the interval ref is lost
I made a working sample of your code here : https://codepen.io/aSH-uncover/pen/wvmYdNy
Addintionnaly you should clean the interval when the component is destroyed by returning the cleanInterval call in the hook that created the inteerval
const Card = ({ step }) => {
const intervals = useRef({})
const [users, setUsers] = useState(40)
useEffect(() => {
intervals.users = setInterval(() => {
setUsers((prevUsers) => prevUsers = prevUsers step)
}, 200)
return () => clearInterval(intervals.users)
}, [])
useEffect(() => {
if (users >= 5000) {
clearInterval(intervals.users)
}
}, [users])
return (<div>number of users {users} </div>)
}
CodePudding user response:
I came up with this. You can try it out. Although there are many ways suggested above
const [users, setUsers] = useState(40);
const [max_user, setMaxUser] = useState(true);
let setIntervalUsers: any;
let sprevUsers = 0;
useEffect(() => {
if (max_user) {
setIntervalUsers = setInterval(() => {
sprevUsers = 100;
if (sprevUsers >= 5000) {
setMaxUser(false);
clearInterval(setIntervalUsers);
} else {
setUsers(sprevUsers);
}
}, 200);
}
}, []);
CodePudding user response:
The way how you check for your condition users >= 5000
is not working because users
is not listed as a dependency in your useEffect
hook. Therefore the hook only runs once but doesnt run again when users
change. Because of that you only check for 40 >= 5000
once at the beginning.
An easier way to handle that is without a setInterval
way.
export const Cards = () => {
const [users, setUsers] = useState(40);
useEffect(() => {
// your break condition
if (users >= 5000) return;
const increment = async () => {
// your interval
await new Promise((resolve) => setTimeout(resolve, 200));
setUsers((prevState) => prevState 100);
}
// call your callback
increment();
// make the function run when users change.
}, [users]);
return <p>current number of users {users}</p>
}