I need periodically fetch data and update it to the screen. I have this code:
const [temperature, setTemperature] = useState();
useEffect(() => {
fetch("urlToWeatherData")
.then(function(response) {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
return;
response.json().then(function(data) {
console.log(data[0].temperature);
setTemperature(data[0].temperature);
});
})
.catch(function(err) {
console.log("Fetch Error :-S", err);
});
}, [] );
So, is there any neat way to run it every 15 seconds, in example? Thanks!
Wrap it in an interval, and don't forget to return a teardown function to cancel the interval when the component unmounts:
useEffect(() => {
const id = setInterval(() =>
fetch("urlToWeatherData")
.then(function(response) {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
return;
response.json().then(function(data) {
console.log(data[0].temperature);
setTemperature(data[0].temperature);
});
})
.catch(function(err) {
console.log("Fetch Error :-S", err);
});
), 15000);
return () => clearInterval(id);
}, []);
Just to give a different approach, you can define a custom hook for extracting this functionality into a reusable function:
const useInterval = (callback, interval, immediate) => {
const ref = useRef();
// keep reference to callback without restarting the interval
useEffect(() => {
ref.current = callback;
}, [callback]);
useEffect(() => {
// when this flag is set, closure is stale
let cancelled = false;
// wrap callback to pass isCancelled getter as an argument
const fn = () => {
ref.current(() => cancelled);
};
// set interval and run immediately if requested
const id = setInterval(fn, interval);
if (immediate) fn();
// define cleanup logic that runs
// when component is unmounting
// or when or interval or immediate have changed
return () => {
cancelled = true;
clearInterval(id);
};
}, [interval, immediate]);
};
Then you can use the hook like this:
const [temperature, setTemperature] = useState();
useInterval(async (isCancelled) => {
try {
const response = await fetch('urlToWeatherData');
// check for cancellation after each await
// to prevent further action on a stale closure
if (isCancelled()) return;
if (response.status !== 200) {
// throw here to handle errors in catch block
throw new Error(response.statusText);
}
const [{ temperature }] = await response.json();
if (isCancelled()) return;
console.log(temperature);
setTemperature(temperature);
} catch (err) {
console.log('Fetch Error:', err);
}
}, 15000, true);
We can prevent the callback from calling setTemperature() if the component is unmounted by checking isCancelled(). For more general use-cases of useInterval() when the callback is dependent on stateful variables, you should prefer useReducer() or at least use the functional update form of useState().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With