Reputation: 633
I'm trying to use ref API many times with setInterval method but only one is working
I have created a ref as an array then I'm trying to insert the function to the array by using the index key but that works only for the first insert I don't know what I'm doing wrong
here's what I've achieved
import React, { useState, useEffect, useRef, createRef } from "react";
import ReactDOM from "react-dom";
function Counter() {
const [countSec, setCountSec] = useState(0);
const [countMin, setCountMin] = useState(0);
useInterval(() => {
setCountSec(countSec + 1); // this working
}, 1000, 0);
useInterval(() => {
setCountMin(countMin + 1); // it's not working
}, 1100, 1);
return <div>
<h1>{countSec} Secounds</h1>
<h1>{countMin} Half-Minutes</h1>
</div>;
}
function useInterval(callback, delay,index){
const savedCallback = useRef([...Array(2)].map(()=> createRef()));
// Remember the latest function.
useEffect(() => {
savedCallback.current[index].current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
let id = setInterval(()=>savedCallback.current[index].current(), delay);
return () => clearInterval(id);
});
};
https://codesandbox.io/s/sharp-tree-k39ts
Upvotes: 2
Views: 2502
Reputation: 2833
There is no need to try to remember multiple callbacks in your useRef
. Everytime you use useInterval
it creates a new instance of your hook. So they will work independently from eachother. This means the first time you use useInterval
it will create a new useRef
for your setCountSec(countSec + 1)
callback. And the second time you use useInterval
it will create another instance of useRef
for your setCountMin(countMin + 1)
. All you have to do it change the interval
to have the second one update once every 30 seconds.
import React, { useState, useEffect, useRef, createRef } from "react";
import ReactDOM from "react-dom";
function Counter() {
const [countSec, setCountSec] = useState(0);
const [countMin, setCountMin] = useState(0);
useInterval(() => {
setCountSec(countSec + 1);
}, 1000); // update every 1000ms (1sec)
useInterval(() => {
setCountMin(countMin + 1);
}, 30000); // update every 30000ms (30sec)
return <div>
<h1>{countSec} Secounds</h1>
<h1>{countMin} Half-Minutes</h1>
</div>;
}
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest function.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
Upvotes: 2
Reputation: 537
Based on your comment
you need to update
countMin
aftercountSec
Here is an working code
function Counter() {
const [countSec, setCountSec] = useState(0);
const [countMin, setCountMin] = useState(0);
useEffect(()=>{
setInterval(() => {
setCountSec(countSec + 1); // this working
}, 1000);
setInterval(() => {
setCountMin(countMin + 1); // it's not working
}, 1100);
}, [])
return <div>
<h1>{countSec} Secounds</h1>
<h1>{countMin} Half-Minutes</h1>
</div>;
}
few pointers on your code would be for every rerender the whole function would get called and a new setInterval would be created...
useEffect(()=>{},[])
is equivalent to componentDidMount
if you want to follow your patten without this useEffect(()=>{},[])
you could use setTimeout
Upvotes: 0