React-calendar: calendar don't update view when value change to other month

Created on 22 Mar 2020  路  10Comments  路  Source: wojtekmaj/react-calendar

When I change value of date in current month calendar update view. But when value in new month, calendar still show current month.

question

Most helpful comment

Have the same issue, version is "^3.0.1". And the trick above solves this issue but give the new one. Arrows which switches the months doesn't work.

All 10 comments

I don't understand, can you rephrase? Or perhaps record the problem you're having?

example: today is Mar-23. Calendar show Mar-2020.

  • when I set value in Mar, calendar show Mar, it correct.
  • when I set value in Feb, calendar still show Mar, I'm expect it show Feb

Which version are you using? Can't reproduce on newest one.

My version ["react-calendar":]"^3.0.0",
<Calendar minDetail="month" maxDetail="month" onClick={this.onClickDate} onChange={this.onChangeDate} locale={'en-EN'} value={start_date} />);

In Mar it ok.
https://pasteboard.co/J0wvRi5.png
Problem when change value to Feb
https://pasteboard.co/J0wwBwx.png

Note:

  • problem happen when I click to calendar, if I don't click to calendar, it work fine.
  • If I have trick activeStartDate={moment(start_date).startOf('month').toDate()} => it work fine.

Have the same issue, version is "^3.0.1". And the trick above solves this issue but give the new one. Arrows which switches the months doesn't work.

Is the issue getting fixed? I am facing the same issue. I have used a separate button to jump to today's date. When passing today's date as value, it gets selected but the month doesn't change. Month needs to be changed manually.

I have also encountered this annoying issue.
When value is updated the view doesn't update (i.e. it doesn't jump to the correct month).

I added the activeStartDate prop that resolves the issue but rises a new one - navigation is disabled ( probably should be a new issue).

@ElektroWenik
Do you have a W/A how month can be updated auto or how to enable navigation with activeStartDate?

@TemaniH i don't remember exactly how i resolved the issue, so here is the code of my component, hope it will help. input arg assume the react-final-form interface.

import React, { useState, useRef, useEffect } from 'react';
import Calendar from 'react-calendar';
import SVG from 'react-inlinesvg';
import clsx from 'clsx';
import { useClickOutside } from '@hooks';
import { Button } from '@components/partials';
import { RadioField } from '@components/form';
import moment from 'moment';

import ArrowLeftIcon from '@icons/form/calendar/arrow_left.svg'
import ArrowRightIcon from '@icons/form/calendar/arrow_right.svg'
import ArrowDownIcon from '@icons/form/calendar/arrow_down.svg'
import { Field } from 'react-final-form';

const defaultActionComponent = ({ toggleCalendar, value }) => (
    <button type="button" className="bz-calendar__default-action" onClick={toggleCalendar}>
        {`${moment(value.start).format('DD-MM-YYYY')} - ${moment(value.end).format('DD-MM-YYYY')}`}
        <SVG className="bz-calendar__default-action__arrow" src={ArrowDownIcon}/>
    </button>
);

const DoubleView = ({ input, actionComponent = defaultActionComponent, float = 'left', periods, onApply }) => {
    const [showCalendar, setShowCalendar] = useState(false);
    const [value, setValue] = useState(input.value);
    const [month, setMonth] = useState(input.value);

    const calendar = useRef(null);

    const openCalendar = () => setShowCalendar(true);
    const closeCalendar = () => setShowCalendar(false);
    const toggleCalendar = () => setShowCalendar(!showCalendar);

    useEffect(() => {
        setMonth(value);
        input.onChange(value);
    }, [value]);

    const onStartChange = val => setValue({ ...value, start: val });
    const onEndChange = val => setValue({ ...value, end: val });

    const onTodayClick = () => setValue({ start: new Date(), end: new Date()});
    const onYesterdayClick = () => {
        const yesterday = moment().add(-1, 'days').toDate();
        setValue({ start: yesterday, end: yesterday});
    };
    const on7daysClick = () => setValue({ start: moment().add(-7, 'days').toDate(), end: new Date()});
    const on14daysClick = () => setValue({ start: moment().add(-14, 'days').toDate(), end: new Date()});
    const on30daysClick = () => setValue({ start: moment().add(-30, 'days').toDate(), end: new Date()});
    const on60daysClick = () => setValue({ start: moment().add(-60, 'days').toDate(), end: new Date()});
    const on90daysClick = () => setValue({ start: moment().add(-90, 'days').toDate(), end: new Date()});
    const onYTDClick = () => setValue({ start: moment().startOf('year').toDate(), end: new Date()});

    useClickOutside(calendar, closeCalendar);

    // Fix calendar issue
    const switchMonth = (calendar, step) => setMonth({ ...month, [calendar]: moment(month[calendar]).add(step, 'months') });

    const NextArrow = calendar => <SVG onClick={() => switchMonth(calendar, 1)} src={ArrowRightIcon}/>;
    const PrevArrow = calendar => <SVG onClick={() => switchMonth(calendar, -1)} src={ArrowLeftIcon}/>;

    const calendarClasses = clsx(
        'bz-calendar',
        'bz-calendar_double',
        {
            'bz-calendar_show': showCalendar,
            'bz-calendar_float_right': float === 'right'
        }
    );

    return (
        <div className="bz-calendar__container" ref={calendar}>
            <div className="bz-calendar__action-component">
                {actionComponent({ value: input.value, openCalendar, closeCalendar, toggleCalendar })}
            </div>
            <div className={calendarClasses}>
                <div className="bz-calendar__head">
                </div>
                <div className="bz-calendar__body">
                    {Boolean(periods) &&
                        <div className="periods">
                            <div className="periods__title">
                                Periodicity
                            </div>
                            <Field className="periods__item" name="periodicity" type="radio" label="By day" value="day" component={RadioField}/>
                            <Field className="periods__item" name="periodicity" type="radio" label="By week" value="week" component={RadioField}/>
                            <Field className="periods__item" name="periodicity" type="radio" label="By month" value="month" component={RadioField}/>
                        </div>}
                    <Calendar
                        activeStartDate={moment(month.start).startOf('month').toDate()} // Fix calendar issue
                        next2Label={null}
                        prev2Label={null}
                        nextLabel={NextArrow('start')}
                        prevLabel={PrevArrow('start')}
                        minDetail="month"
                        value={input.value.start}
                        onChange={onStartChange}
                        maxDate={input.value.end}
                        className="react-calendar_start"
                    />
                    <Calendar
                        activeStartDate={moment(month.end).startOf('month').toDate()} // Fix calendar issue
                        next2Label={null}
                        prev2Label={null}
                        nextLabel={NextArrow('end')}
                        prevLabel={PrevArrow('end')}
                        minDetail="month"
                        value={input.value.end}
                        onChange={onEndChange}
                        minDate={input.value.start}
                        className="react-calendar_end"
                    />
                    <div className="helpers">
                            <div className="helpers__row">
                                <Button onClick={onTodayClick}>Today</Button>
                                <Button onClick={onYesterdayClick}>Yesterday</Button>
                            </div>
                            <div className="helpers__row">
                                <Button onClick={on7daysClick}>7 days</Button>
                                <Button onClick={on14daysClick}>14 days</Button>
                            </div>
                            <div className="helpers__row">
                                <Button onClick={on30daysClick}>30 days</Button>
                                <Button onClick={on60daysClick}>60 days</Button>
                            </div>
                            <div className="helpers__row">
                                <Button onClick={on90daysClick}>90 days</Button>
                                <Button onClick={onYTDClick}>YTD</Button>
                            </div>
                            <div className="helpers__row">
                                <Button className="helpers__apply" onClick={onApply ? onApply : closeCalendar}>Apply</Button>
                            </div>
                    </div>
                </div>
            </div>
        </div>
    );
};


export default DoubleView;

I created a demo with the issue - react-datetimepicker-update-view
steps to reproduce:

  • select a date not in the current view
  • reset the date (set new value)
  • reopen the calendar
  • old view will be displayed while expected to see the new selected value.

Found a nice workaround, took it from the test page( commented in the demo above ):

  // need to update both fields - value and activeStartDate - so it will jump to correct view after selection (solves the view issue)
  const onFullChange = (date) => {
    onValue(date);
    onActiveStartDate(date);
  };

  // need to update activeStartDate as we are now handling its value (solves navigation issue)
  const onViewOrDateChange = ({ activeStartDate, view }) => {
    onActiveStartDate(activeStartDate);
  };

  return (
    <div>
      <DateTimePicker
        onChange={onFullChange}
        onActiveStartDateChange={onViewOrDateChange}
        activeStartDate={activeStartDate}
        value={value}
      />
      <br />
      <button onClick={resetDate}>Reset Date</button>
    </div>
  );

Would be nice if this could be the default behaviour, i.e. view will be updated according to selected value, and we dont have to manually handle the activeStartDate.

maybe check if value was changed but activeStartDate wasn't then override activeStartDate with value?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tranvula picture tranvula  路  4Comments

rmccue picture rmccue  路  4Comments

fasmart4 picture fasmart4  路  6Comments

boonware picture boonware  路  4Comments

Hubro picture Hubro  路  3Comments