I have the following simple set up:
<Calendar
onDayPress={day => onChangeDate(day)}
monthFormat={'MMMM yyyy'}
/>
When the calendar renders I click the forward month arrow, then select a date. In my onChangeDate function I store that date in state. Doing that causes the calendar to re-render and it resets to the original default month. If I use markedDates and set the selected date as selected I can see it selected, when I scroll back to the correct month, but this is pretty useless for me since the calendar resets back to the default month as soon as I select any date outside that default month.
Hi, please check example app because it has exactly the usecase you defined and works ok. Also if you need to force calendar to show specific month use current prop
That was not a helpful response.
sorry for that, if you could give full code example with this problem manifesting it would be easier to understand your problem and reproduce it
I've tried to trim down my code as much as possible to where it still exhibits the behavior I explained. At this point, I'm pretty sure it's because I'm using it in the ListHeaderComponent of a FlatList. I'm not sure why that causes the behavior or how to fix it, though. With the way my screen is laid out, I don't really have an alternative.
import React, { Component } from 'react';
import { View, StatusBar, FlatList, RefreshControl } from 'react-native';
import { Calendar, CalendarList, Agenda } from 'react-native-calendars';
import { connect } from 'react-redux';
import moment from 'moment';
import { Header, Text } from '../../components';
import styles from './styles';
class CalendarScreen extends Component {
state = { selectedDate: moment() }
selectDate(calendarDay){
const date = moment(calendarDay.dateString);
this.setState({ selectedDate: date });
}
refresh(){
}
render() {
const { navigation, nav } = this.props;
const { selectedDate } = this.state;
const loading = false;
const items = [];
let markedDates = {};
markedDates[selectedDate.format('YYYY-MM-DD')] = { selected: true };
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<Header navigation={navigation} title="CALENDAR" />
<FlatList data={items}
refreshing={loading}
onRefresh={() => this.refresh()}
refreshControl={
<RefreshControl tintColor="transparent" colors={['transparent']} style={{backgroundColor: 'transparent'}}
refreshing={loading}
onRefresh={() => this.refresh()} />
}
ListHeaderComponent={() => (
<View style={styles.listHeader}>
<Calendar style={{ marginTop: 50 }}
markedDates={markedDates}
onDayPress={day => this.selectDate(day)}
monthFormat={'MMMM yyyy'}
/>
<View style={styles.selectedDayHeading}>
<Text style={styles.selectedDayHeadingText}>{moment(selectedDate).format('MMMM Do, YYYY').toUpperCase()}</Text>
</View>
</View>
)}
renderItem={({ item, index }) => (
<Text>{item.title}</Text>
)}
keyExtractor={(item,index) => item.id}
/>
</View>
);
}
}
const mapStateToProps = state => {
return { };
};
export default connect(mapStateToProps)(CalendarScreen);
Have you solve this problem? i have the same thing...
Hi, I have investigated this bug. It looks like the problem is that each time the FlatList is rerendered calendar component is being constructed (constructor is being called). That is the reason the calendar forgets current month. Not sure why this happens in flatlist.
However there is a workaround to solve this. You could add property current = {(this.state.selectedDate && selectedDate.format('YYYY-MM-DD')) || new Date()} to calendar. This would achieve the result you want. Event if calendar is constructed on each day press it would get selected day as current month and would show correct month. However you should consider that having calendar to be reinitialized on each day press could somewhat impact your app performance.
@Doskulov @tautvilas I actually did figure out what was going on with this. It has to do with RN's diffing algorithm. Basically, what I did was instead of inlining the calendar in the FlatList's ListHeaderComponent I broke it out into a function, like this:
ScheduleHeader = () => {
const { loading, selectedDate, schedules, datesWithEvents, visibleEvents } = this.state;
return (
<View style={styles.listHeader}>
<ScheduleSelector schedules={schedules} />
<CalendarHeader selectedDate={selectedDate} onChangeDate={day => this.selectDate(day)} datesWithEvents={datesWithEvents} />
<View style={styles.selectedDayHeading}>
<Text style={styles.selectedDayHeadingText}>{moment(selectedDate).format('MMMM Do, YYYY').toUpperCase()}</Text>
</View>
</View>
);
};
and then changed my FlatList like so:
ListHeaderComponent={this.ScheduleHeader}
I still don't fully understand what the difference is, but basically this prevents the FlatList from thinking that the ListHeaderComponent needs to be redrawn.
@tautvilas your solution actually does not work.
I tried your code and I get a "selectedDay not defined" function.
I tried with:
current = {(this.state.selectedDate && this.state.selectedDate.format('YYYY-MM-DD')) || new Date()}
but I get a "this.state.selectedDate.format is not a function" error
it actually works with this code
{(this.state.selectedDate) || new Date()}
without the format check
Hi,
I'm facing the same issue,
When ever I'm using 'current' attribute, when I click on the arrow it redraws the default month.
When I remove the 'current' attribute the redrawing issue is solved.
But I need the 'current' attribute to full my requirement.
Has anybody solved this issue?
This could be achieved by setState or mobx/redux.
it actually works with this code
{(this.state.selectedDate) || new Date()}
without the format check
Thank you, this solved my redraw issue!
Most helpful comment
Hi, I have investigated this bug. It looks like the problem is that each time the FlatList is rerendered calendar component is being constructed (constructor is being called). That is the reason the calendar forgets current month. Not sure why this happens in flatlist.
However there is a workaround to solve this. You could add property
current = {(this.state.selectedDate && selectedDate.format('YYYY-MM-DD')) || new Date()}to calendar. This would achieve the result you want. Event if calendar is constructed on each day press it would get selected day as current month and would show correct month. However you should consider that having calendar to be reinitialized on each day press could somewhat impact your app performance.