I'm working on a scheduling web application.
I am trying to implement a feature that detects the total hours between two times, startTime and endTime, which are selected on a form and stored via the useState hook:
const [startTime, setStartTime] = useState("")
const [endTime, setEndTime] = useState("")
const [totalHours, setTotalHours] = useState(0)
The end goal is to calculate and print the total hours between both times next to "totalHours:" in the UI: Image of UI for selecting start, end times and total hours
My Issue: The onChange event is only updating startTime and endTime to the PREVIOUS state whenever I update their respective fields on the form.
For example, both start at "12:00AM". If I change the startTime to "1:00AM", when I read startTime using console.log(startTime)
, it prints "NaN". If I then change startTime a second time, say to "2:00AM", console.log(startTime)
prints "1:00AM"
I tried googling this and only found other threads referring the state as a component prop, nothing that uses the useState hook:
react useState hook variable value don't update on input onChange event
React setState not Updating Immediately
My understanding is that the setter functions for the useState hook, e.g. setStartTime() and setEndTime(), run asynchronously and cause this error.
I would appreciate any help.
my React/Typescript code:
The form HTML:
return(
<form>
...
<label>
startTime:
{/* <input type="text" className={inputStyle} onChange={(e) => setStartTime(e.target.value)}/> */}
<div id="selectStartTime">
<select className={inputStyle} name="startTimeHour" id="startTimeHour"
onChange={(e) => handleStartTimeChange(e.target.value)}> {/*set the time AND calculate total hours*/}
<option value="12:00AM">12:00AM</option>
<option value="1:00AM">1:00AM</option>
<option value="2:00AM">2:00AM</option>
<option value="3:00AM">3:00AM</option>
<option value="4:00AM">4:00AM</option>
<option value="5:00AM">5:00AM</option>
<option value="6:00AM">6:00AM</option>
<option value="7:00AM">7:00AM</option>
<option value="8:00AM">8:00AM</option>
<option value="9:00AM">9:00AM</option>
<option value="10:00AM">10:00AM</option>
<option value="11:00AM">11:00AM</option>
<option value="12:00PM">12:00PM</option>
<option value="1:00PM">1:00PM</option>
<option value="2:00PM">2:00PM</option>
<option value="3:00PM">3:00PM</option>
<option value="4:00PM">4:00PM</option>
<option value="5:00PM">5:00PM</option>
<option value="6:00PM">6:00PM</option>
<option value="7:00PM">7:00PM</option>
<option value="8:00PM">8:00PM</option>
<option value="9:00PM">9:00PM</option>
<option value="10:00PM">10:00PM</option>
<option value="11:00PM">11:00PM</option>
</select>
</div>
</label>
<br/>
<label>
endTime:
{/* <input type="text" className={inputStyle} onChange={(e) => setEndTime(e.target.value)}/> */}
<div id="selectEndTime">
<select className={inputStyle} name="endTimeHour" id="endTimeHour"
onChange={(e) => handleEndTimeChange(e.target.value)}> {/*set the time AND calculate total hours*/}
<option value="12:00AM">12:00AM</option>
<option value="1:00AM">1:00AM</option>
<option value="2:00AM">2:00AM</option>
<option value="3:00AM">3:00AM</option>
<option value="4:00AM">4:00AM</option>
<option value="5:00AM">5:00AM</option>
<option value="6:00AM">6:00AM</option>
<option value="7:00AM">7:00AM</option>
<option value="8:00AM">8:00AM</option>
<option value="9:00AM">9:00AM</option>
<option value="10:00AM">10:00AM</option>
<option value="11:00AM">11:00AM</option>
<option value="12:00PM">12:00PM</option>
<option value="1:00PM">1:00PM</option>
<option value="2:00PM">2:00PM</option>
<option value="3:00PM">3:00PM</option>
<option value="4:00PM">4:00PM</option>
<option value="5:00PM">5:00PM</option>
<option value="6:00PM">6:00PM</option>
<option value="7:00PM">7:00PM</option>
<option value="8:00PM">8:00PM</option>
<option value="9:00PM">9:00PM</option>
<option value="10:00PM">10:00PM</option>
<option value="11:00PM">11:00PM</option>
</select>
</div>
</label>
<br/>
<label>
totalHours: {}
</label>
...
</form>
The handler functions for onChange:
const handleStartTimeChange = (time: string) => {
setStartTime(time);
calculateTotalHours();
}
const handleEndTimeChange = (time: string) => {
setEndTime(time);
calculateTotalHours();
}
The function that calculates the total hours between startTime and endTime (This is where I console.log to see that the error is happening)
// calculate total hours based on start and end time
const calculateTotalHours = () => {
// convert strings as times to ints with values from 0 to 23 to represent 24 hour time
// where 0 = 12am and 23 = 11pm
// NOTE: This is where I see my error occuring
console.log(startTime, endTime)
// Get hours value
// All values before ":", split time by colon and get first value, convert to int
let startTimeValue = parseInt(startTime.split(":")[0]);
let endTimeValue = parseInt(endTime.split(":")[0]);
// if either time is 12, remove 12 hours
if (startTimeValue === 12) {
startTimeValue -= 12;
}
if (endTimeValue === 12) {
endTimeValue -= 12;
}
// if either time has PM, add 12 hours respectively
if (startTime.includes("PM")) {
startTimeValue += 12;
}
if (endTime.includes("PM")) {
endTimeValue += 12;
}
// calculate time between start and end times
const total = endTimeValue - startTimeValue;
// if that value is negative, return 0.
if (totalHours < 0) {
const total = 0;
setTotalHours(total);
}
// else, return the value
setTotalHours(total);
}