0

So, I am creating a select month and date View in react native. I have to change the date dynamically based on the month selected so that the user can't select a date like 31st Feb. So I have created two states namely month and dateList storing month and list of dates and i am updating this dateList state as soon as the user changes the month. The problem is that the inside return statement we already render the two states and the updated date state shows in the next render and not in the same render.

return (
 <View style={{flexDirection : "row"}}>
   <View style={styles.setTime}>
     <CustomFilterMenu list={months} onPress={changeDate} item={month} setItem= {setMonth}/>
   </View>
   <View style={styles.setTime}>
      <CustomFilterMenu list={dateList} item={date} setItem={setDate} />
   </View>
 </View> 
)

const changeDate = () => {
   setDateList(getDateArray(month));
}

Here all the functions are working well. getDateArray() is a helper function that returns the date array required. Here dateList, data, month are all the react useStates.

So what is actually happening is that this component is first triggered to render which renders the date according to dateList data. So this date View is rendered now. Now if i change the month state, it triggers the changeDate() function which in turn changes the dateList array. However this change happens after everything is rendered. So, it doesn't show up any changes in the date View just now. However when i again change the month, it causes re render and now the date array corresponding to the previous dateList array is shown. So basically the date View is one render behind the month View.

Can you tell me any other way to do this because i don't think this is gonna working this way. Thank you.

1 Answers1

0

You dont need to store the days of a month because the Date class can tell you the days in a month if you just have the month and the year. With that in mind all you really need to do is useEffect to listen for month and year changes and then change day to reflect this. Try it out on snack:

const MONTHS = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
]
// create array of ints of size len
// with the first value being startInt
const numberRange=(len,startInt=0)=>{
  return new Array(len).fill(null).map((nul,i)=>i+startInt)
}

// given month and year it will get number of days in a month
// https://stackoverflow.com/questions/315760/what-is-the-best-way-to-determine-the-number-of-days-in-a-month-with-javascript
const daysInMonth=(month,year)=>{
  let monthInt = MONTHS.findIndex(m=>m==month)+1
  return new Date(year,monthInt,0).getDate()
}

export default function App(props){
  const [month, setMonth] = useState('June');
  const [day,setDay] = useState(22);
  const [year, setYear] = useState(2022);
  const maxDays = daysInMonth(month,year)
  // when month or year changes make sure day doesnt exceed value
  useEffect(()=>{
    if(day > maxDays)
      setDay(maxDays)
  },[month,year])
  return (
    <View style={styles.container}>
      <Text>{month} {day}, {year}</Text>
      <Text>Days in month: {maxDays}</Text>
      <View style={styles.row}>
        <Picker
          style={{width:'30%'}}
          label="Month" 
          items={MONTHS}
          onSelection={setMonth}
          value={month}
        />
        <Picker
          style={{width:'25%'}}
          label="Day" 
          items={numberRange(maxDays,1)}
          onSelection={setDay}
          value={day}
        />
        <Picker
          style={{width:'30%'}}
          label="Year" 
          items={numberRange(25,2000)}
          onSelection={setYear}
          value={year}
        />
      </View>
    </View>
  )
}
PhantomSpooks
  • 2,877
  • 2
  • 8
  • 13
  • Oops i just figured it out. Actually I also used almost the same approach, but in the `daysInMonth` function, I didn't added +1 in `month` variable since I thought the indexing is 0 based and thus my function for getting the actual number of days was the only problem. Thanks :) – Deepak Sangle Jun 22 '22 at 20:17