Custom DatePicker CalendarWidget component when placed inside form element, is resetting state when re-render happens upon valid change like picking a date. If taken out of form tag, the widget is retaining updated state correctly. Since ui is re-rendered on state change, form element is also re-rendered and all its children like the CalendarWidget is resetting. How to ensure the state i.e. to say the user clicked date on CalendarWidget is retained when it is placed inside the form tag?
App.js
import './App.css';
import React, {useEffect, useState} from 'react';
import CalendarWidget from './CalendarWidget';
var myMap = new Map();
function App() {
const[loading, setLoading] = useState(true);
const[fromDate, setFromDate] = useState(new Date())
const[toDate, setToDate] = useState(new Date())
const[disabledFromAndToDates, setDisabledFromAndToDates] = useState([]);
const[roomsList, setRoomsList]=useState([])
const[currentRoomSelected , setCurrentRoomSelected]=useState(0)
useEffect(() => {
setLoading(true);
var data =
[{"roomNumber":1,"bookingDates":[]},
{"roomNumber":2,"bookingDates":[]},
{"roomNumber":3,"bookingDates":[]},
{"roomNumber":4,"bookingDates":
[{"bookingId":6,"fromDate":"2022-08-19","toDate":"2022-08-22","fromTime":"17:27:22","toTime":"17:27:22"}]},
{"roomNumber":5,"bookingDates":
[{"bookingId":1,"fromDate":"2022-08-16","toDate":"2022-08-18","fromTime":"17:27:17","toTime":"17:27:17"},
{"bookingId":3,"fromDate":"2022-08-26","toDate":"2022-08-28","fromTime":"17:27:19","toTime":"17:27:19"}]},
{"roomNumber":6,"bookingDates":
[{"bookingId":4,"fromDate":"2022-08-14","toDate":"2022-08-15","fromTime":"17:27:20","toTime":"17:27:20"},
{"bookingId":7,"fromDate":"2022-08-14","toDate":"2022-08-18","fromTime":"17:27:22","toTime":"17:27:22"}]},
{"roomNumber":7,"bookingDates":[]},
{"roomNumber":8,"bookingDates":
[{"bookingId":5,"fromDate":"2022-08-20","toDate":"2022-08-21","fromTime":"17:27:21","toTime":"17:27:21"}]},
{"roomNumber":9,"bookingDates":[]},
{"roomNumber":10,"bookingDates":
[{"bookingId":2,"fromDate":"2022-08-13","toDate":"2022-08-19","fromTime":"17:27:19","toTime":"17:27:19"}]}]
Object.entries(data).forEach(([key, value]) => {
if(myMap.has(value.roomNumber)){
if(value.bookingDates.length>0)
myMap.get(value.roomNumber).push(value.bookingDates)
}
else{
myMap.set(value.roomNumber, [])
myMap.get(value.roomNumber).push(value.bookingDates)
}
})
//setCurrentRoomSelected(1)
setRoomsList([...myMap.keys()])
setFromAndToDatesForCurrentRoom([...myMap.keys()][0])
setLoading(false)
}, []);
function setFromAndToDatesForCurrentRoom(roomNumber){
console.log(roomNumber)
var value = myMap.get(roomNumber);
if(value[0].length>0)
setDisabledFromAndToDates(oldVal => value[0].map(({bookingId, fromTime, toTime, ...keepAttrs}) => keepAttrs))
else
setDisabledFromAndToDates(oldVal => [])
}
if (loading) {
return <p>Loading...</p>;
}
function fromDateChangeHandler(date) {
setFromDate(date);
}
function toDateChangeHandler(date) {
setToDate(date);
}
function loadCalendar(roomNoSelected){
console.log("entering..."+roomNoSelected.item)
setCurrentRoomSelected(prevVal => roomNoSelected.item)
setFromAndToDatesForCurrentRoom(roomNoSelected.item)
}
const rooms = roomsList.map( item => {
return (<button className='room' id={item} key={item} onClick={() => loadCalendar({item})}>Room No {item}</button>)
})
return (
<div className="App">
<form>
<h1 className='text-center'>Booking App</h1>
<div>{rooms}</div>
<CalendarWidget
key="calendarWidget"
fromDate={fromDate}
toDate={toDate}
disabledFromAndToDates={disabledFromAndToDates}
onFromDateChange={fromDateChangeHandler}
onToDateChange={toDateChangeHandler}
/>
</form>
</div>
)
}
export default App;
CalendarWidget.js
import React from 'react'
import Calendar from 'react-calendar'
import './Calendar.css';
import './App.css';
export default function CalendarWidget(props) {
const fromDate = props.fromDate
const toDate = props.toDate
const disabledFromAndToDates = props.disabledFromAndToDates
function TilesDisabled({date, view}){
var flag = false;
if(view==='month'){
date = new Date(formatDate(date))
if(disabledFromAndToDates.length>0){
for (var i = 0; i < disabledFromAndToDates.length; i++) {
let disabledDates = disabledFromAndToDates[i]
if(date >= new Date(disabledDates.fromDate) && date <= new Date(disabledDates.toDate)){
flag=true;
break;
}
}
}
}
return flag;
}
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
function onFromDateChangeHandler(date) {
props.onFromDateChange(date);
}
function onToDateChangeHandler(date) {
props.onToDateChange(date);
}
return(
<div className='DatePicker'>
<span className='CalendarWidget1'>
<div className='calendar-container'>
<Calendar onChange={onFromDateChangeHandler} value={fromDate} tileDisabled={TilesDisabled}/>
</div>
<p className='text-center'>
<span className='bold'>Selected From Date:</span>{' '}
{fromDate.toDateString()}
</p>
</span>
<span className='CalendarWidget2'>
<div className='calendar-container'>
<Calendar onChange={onToDateChangeHandler} value={toDate} tileDisabled={TilesDisabled}/>
</div>
<p className='text-center'>
<span className='bold'>Selected To Date:</span>{' '}
{toDate.toDateString()}
</p>
</span>
</div>
)
}
I need help with the code above in the 2 js files, as to what changes to make to get the desired functionality. I would like to know if this is possible with plain form tag or if i need another react library that supports forms etc or if I have to correct the existing code in some way. The dependency package I used for DatePicker is react-calendar 3.7.0