React useState Initialization - Hard-coded versus Calculated values

I am trying to implement a countdown, and I just cannot grasp the basics of React.

React.useState() works if I use a hard-coded value, but if I try to pass something from the app, nothing displays.

modelUpdate() works if I use a hard-coded value when I update, but not if I try to calculate the next number.

I am open to any alternate implementation, but the below shows what I have tried, and what works and what doesn't. I don't know if I just can't figure out the syntax or what.

////////////////////////////////////////////////
const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) => {

// HARD-CODED STARTING VALUE WORKS
const [timerId, setTimerId] = React.useState(0)

// INITIALIZATION BASED ON PASSED-IN VALUES **DOESN'T** WORK
//const [myVar, setMyVar] = React.useState({model.var1})

function scheduledUpdate() {

  // HARD-CODED UPDATE WORKS
  modelUpdate({var1: 2})
  
  // CALCULATED UPDATE **DOESN'T** WORK
  //modelUpdate({var1: var1 + 1})

  // DIFFERENT SYNTAX FOR CALCULATED UPDATE ALSO **DOESN'T** WORK
  //moduleUpdate({var1: {var1} + 1})
  //moduleUpdate({var1: {model.var1} + 1})

  // THIS CALCULATED UPDATE DOES WORK
  setTimerId( timerId + 1 )

}

React.useEffect(() => {
setInterval( scheduledUpdate, 1000 );
}

return (

  <div className="card">{timerId}</div>

);
}

////////////////////////////////////////////////
Furthermore, the timer that counts up in my example, seems to scroll through all possible values until it lands on the latest value. I don't understand that either. Am I not using React correctly regarding the setState functionality?

Ok. I figured out the previous problem. But, now I have a new problem. The check if data.started is false is not keeping setData() from being called more than once, so setInterval can kick off more than one countdown, which results in strange countdown behavior. Any suggestions?

const Countdown = ({totalSeconds}) => {

/////////////////////////////////////////////////////////////////////////////////////////////////
const initialState = {
started: false,
timerId: 0,
seconds: totalSeconds // THIS IS HOW I CAN ACCESS A DYNAMIC START VALUE NOW
}
const [data, setData] = React.useState( initialState )
/////////////////////////////////////////////////////////////////////////////////////////////////

function countdown() {
if ( data.seconds === 0 ) {
// Countdown over...
clearInterval( timerId )
setData({ started: data.started, timerId: 0, seconds: data.seconds })
}
else {
setData({ started: data.started, timerId: data.timerId, seconds: data.seconds - 1 })
}
}

React.useEffect(() => {
/////////////////////////////////////////////////////////////////////////////////////////////////
// NEW PROBLEM: I THINK THERE IS ASYNCHRONOUS ACCESS TO data.started
// WHICH IS CAUSING STRANGE BEHAVIOR ON MY COUNTDOWN.

 if ( data.started === false ) {
   setData({ started: true, timerId: setInterval( countdown, 1000 ), seconds: data.seconds })
 }

})

return (

 <div><h2>{data.seconds}</h2></div> 

)
}

const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) => {

return (
<div className="card">
  <Countdown totalSeconds={model.seconds} />
</div>

);
}

Final update.... I solved my other problem. I think useEffect was being called every time the state variable changed. The setInterval() didn't actually seem to be making anything happen repeatedly, though it did call countdown once and stop. Neither could setTimeout() be called recursively from within countdown().

But, turns out, I can make useEffect only respond to changes in the variable I care about, and trigger setTimeout every second from there. Seemed to fix the weird jumping around of my counter.

//////////////////////////////////////////////////////////////////////////////////////////

const Countdown = ({totalSeconds}) => {

const initialState = {
seconds: totalSeconds
}
const [data, setData] = React.useState( initialState )

function countdown() {
if ( data.seconds !== 0 ) {
setData({ seconds: data.seconds - 1 })
}
}

React.useEffect(() => {
if ( data.seconds > 0 ) {
setTimeout( countdown, 1000 )
}

}, [data.seconds])

return (

 <div><h2>{data.seconds}</h2></div> 

)
}

const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) => {

return (
<div className="card">
  <Countdown totalSeconds={model.seconds} />
</div>

);
}