onStart is button and when i press it , it must run useeffect but it does not run it in first start but run it on reload. state value change on first start on dev tool.
const [started, setStarted] = useState(false);
const onStart = () => {
setStarted(true);
};
useEffect(() => {
if(started){
let timer = setInterval(() => tick(), 1000);
return () => clearInterval(timer);
}
}, []);
You need to add started to the dependency array of the useEffect.
const [started, setStarted] = useState(false);
const onStart = () => {
setStarted(true);
};
useEffect(() => {
if (started) {
let timer = setInterval(() => tick(), 1000);
return () => clearInterval(timer);
}
}, [started]); // Add started here.
Related
I'm trying to rerender my component every 5 seconds. The problem occurs when I open the page the first time- it shows after 5 seconds. How should I make sure to make my component visible instantly after page is opened?
useEffect(() => {
const getChargersData = () => {
axios.get(API_URL)
.then(res => {
setChargers(res.data);
})
}
const interval = setInterval(() => {
getChargersData()
},5*1000);
return () => clearInterval(interval);
},[]);
call the getChargerData function before the setInterval, this way the data will be available before the first 5s ellapse
useEffect(() => {
const getChargersData = () => {
axios.get(API_URL)
.then(res => {
setChargers(res.data);
})
}
getChargersData()
const interval = setInterval(() => {
getChargersData()
},5*1000);
return () => clearInterval(interval);
},[]);
am writing an app in react native and i got a problem with useState and useEffect hooks. I would like to change increment state value by one every 10 seconds.
Here is my code:
const [tripDistance, setTripDistance] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setTripDistance((prevState) => prevState + 1);
console.log(tripDistance);
}, 10000);
return () => {
clearInterval(interval);
};
}, []);
but the output from the console.log is always 0.
What am I doing wrong?
The output is always zero because in your useEffect you are not listening for the changes on tripDistance state. When you call setTripDistance you cannot access the updated value immediately.
You should add another useEffect that listen on tripDistance in order to have the correct console.log.
So you have to do something like:
const [tripDistance, setTripDistance] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setTripDistance((prevState) => prevState + 1);
}, 10000);
return () => {
clearInterval(interval);
};
}, []);
useEffect(() => console.log(tripDistance), [tripDistance]);
try this
const [tripDistance, setTripDistance] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setTripDistance((prevState) => prevState + 1);
}, 10000);
return () => {
clearInterval(interval);
};
}, [tripDistance]);
const HeroSection = () => {
const [Change,setChange] = useState(false);
useEffect(() => {
setInterval(() => {
setChange(!Change)
}, 5000);
return () => clearInterval();
}, [Change]);
return (
<HeroContainer>
<HeroBg>
<ImageBg src={ Change ? Image1 : Image2 } />
</HeroBg>
</HeroContainer>
)``
}
export default HeroSection
react auto slide images works for the first few times then becomes buggy as in fast paced changes of images regardless of the 5 sec interval
clearInterval(); does nothing. You need to pass the created interval's ID to clearInterval for it to be cleared.
I also don't think the effect hook should have change as a dependency unless you use setTimeout instead.
const [change, setChange] = useState(false);
useEffect(() => {
const timeoutId = setTimeout(() => {
setChange(!change)
}, 5000);
return () => clearTimeout(timeoutId);
}, [change]);
to set a new timeout in the effect callback every time change changes.
Or:
const [change, setChange] = useState(false);
useEffect(() => {
const intervalId = setInterval(() => {
setChange(change => !change)
}, 5000);
return () => clearInterval(intervalId);
}, []);
to set an interval only once, when the component mounts.
const handleClick = () => {
setState({ ...state, on: !state.on });
let tog = state.on;
console.log("first" + tog);
const interval = setInterval(() => {
if (tog) {
console.log(tog);
} else clearInterval(interval);
}, 1000);
};
enter image description here
this one will not be able to stop even the tog is false;
however if I don't use state, change to a variable it will not happen,
it is so weird for me, I need some help;
let flag = true;
const handleClick = () => {
flag = !flag;
console.log("first" + flag);
const interval = setInterval(()=>{
if(flag){
console.log(flag);
}else(clearInterval(interval))
},1000)
};
React will create new handleClick on every re-renders, and there will be different setIntervals,
const intvl = useRef(null);
const handleClick = () => {
intvl.current = setInterval(() => { //now interval is not changing on every fn recreation
.....
clearInterval(intvl.current);
}
check this one
You should use an Effect to handle intervals, something like this:
useEffect(() => {
let intervalId
if (state.on) {
intervalId = setInterval(() => {
console.log(state.on)
}, 1000)
return () => clearInterval(intervalId)
}
}, [state.on])
const handleClick = () => {
setState({ ...state, on: !state.on });
};
working code
From what I can tell, the timer being called in a different scope.. how can I accomplish a function to stop the timer? Going a bit crazy here, thank you for any help.
const SomeComponent = ({ isPlaying }) => {
let timer = null;
React.useEffect(() => {
if (isPlaying) {
startTimer();
}
},[isPlaying]);
const startTimer = () => {
timer = setInterval(() => {
console.log('tick');
}, 1000);
};
const stopTimer = () => {
console.log('stopping timer: ', timer); // shows null, instead of giving the timerId to stop properly
clearInterval(timer);
};
The timer variable will "reset" each time your component is re-rendered. Even if it holds your timer, a re-render will set its value to null again.
You could either move out of the component scope, or use useRef to keep the variable through re-renders:
const SomeComponent = ({ isPlaying }) => {
const timer = React.useRef(null);
React.useEffect(() => {
if (isPlaying) {
startTimer();
}
return () => clearInterval(timer.current);
}, [isPlaying]);
const startTimer = () => {
timer.current = setInterval(() => {
console.log('tick');
}, 1000);
};
const stopTimer = () => {
clearInterval(timer.current);
};
Note that I also force a clearInterval by using a return inside the useEffect. This way the component will automatically "clean up" when it unmounts. I also changed timer to be a constant.