简体   繁体   中英

set time dynamic time for set interval in react

Hello i am struggling to set dynamic time for settimeout function in react js. i have long string of key value pair of time and message. i wants to display each message for specific time and loop through whole list. here is what i am trying, but not working.

const [timer, setTimer] = useState(0)
   const [time, setTime] = useState(5000)// this is default value to start which need to update  with str time value

const str=[{name:"rammy", time:1000},
             {name:"james", time:4000},
             {name:"crown", time:2000}]
            useEffect(()=>{
            const getTime= str[timer].time
            setTime(getTime)

          },[timer]) 
//when timer change it should update  update time state which will be used to update time for time settime out
 
function increment() {  
  useEffect(()=>{    
setTimeout(() => {
  setTimer((ele)=>ele+1)
  
 }, time);
},[timer])
} // above code is for increment time state on each iteration

function ButtonHandle(){
  //setRealString(itr)
  increment()
  
} //button handler for start  timer

First of all, you can't put hooks inside functions (other than your component functions). https://reactjs.org/docs/hooks-rules.html

So take the useEffect out of increment()

useEffect(()=>{
    increment()
},[timer])

function increment() {  
    setTimeout(() => {
        setTimer((ele)=>ele+1)
    }, time);
}

But you also need to clear the timeout. We can return the timeout function to reference it, and clear the time out with a return inside useEffect. Clearing timeouts and intervals in react

useEffect(()=>{
    const myTimeout = increment()

    return () => {
        clearTimeout(myTimeout)
    }
},[timer])

function increment() {

    return setTimeout(() => {
        setTimer((ele) => ele + 1);
    }, time);
}

Then we can combine the useEffects which both have a dependancy array of [timer].

useEffect(() => {
    const getTime = str[timer].time;
    setTime(getTime);

    const myTimeout = increment();

    return () => {
        clearTimeout(myTimeout);
    };
}, [timer]);

You don't need to use useEffect to do it. You misunderstood the useEffect usage, it's a react hook to you implement side-effects and you can't use react-hooks inside a function, it should be in the component scope.

I can increment directly from the ButtonHandle function.

// On the index state is necessary in this implementation
const [index, setIndex] = useState(-1)

const guys=[
  {name: "rammy", time:1000},
  {name: "james", time:4000},
  {name: "crown", time:2000}
]

// useCallback memoize the increment function so that it won't
// change the instance and you can use it in the useEffect 
// dependency array
const increment = useCallback(() => {
  setIndex((i) => i+1)
}, [])

useEffect(() => {
   // change the state if the timer is greater than -1
   if (index !== -1) {
     if (index >= guys.length) {
       setIndex(-1);
     } else {
       setTimeout(() => {
         increment();
       }, guys[index].time); // <-- you get the time from your array
     }
   }
 }, [index, increment]);

 function handleClick(){
   //setRealString(itr)
   increment()
 }

Even though I helped you, I don't know what you're trying to do. This implementation sounds like a code smell. We can help you better if you explain the solution you're trying to do instead of just the peace of code.

You don't need to set the time state, as you already have the time in the array; avoiding unnecessary state changes is good.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM