Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic change of state, doesn't update the calendar view #3901

Open
Behfar90 opened this issue Jan 17, 2023 · 7 comments
Open

Dynamic change of state, doesn't update the calendar view #3901

Behfar90 opened this issue Jan 17, 2023 · 7 comments

Comments

@Behfar90
Copy link

Describe the bug
I have made a semi range-picker using two separate date pickers, and added calendar container to the second one so that I can add some default ranged buttons to it and everything works perfect. The user can either change of dates manually, or using default ranged buttons and then click on "apply" to submit the changes.
The problem is clicking on the buttons does set the start/end states, but the calendar doesn't get updated and shows the old month.
I have replicated the problem out here...
CodeSandBox

To Reproduce

  1. Click anywhere inside the wrapper and you have the pickers popped
  2. Click on the "Last year" button
  3. You see the states (start, end) which are passed as props to the DatePicker changes, but the calendar still shows the wrong month/year

Expected behavior
After step 3, when startDate changes to January 1, 2022, and endDate --> December 30, 2022, calendars should show the correct months/years

Thanks!

@aaronleopold
Copy link

aaronleopold commented Jan 17, 2023

Hello, I'm actually facing a similar issue! I have a slightly simpler use case, where I have a set of selectable options adjacent to a calendar that update the calendar's single date state (instead of a range). E.g. 60 days from now, 90 days from now, etc. When the state changes past the currently viewed month, the frame does not change to view the new month as stated above by @Behfar90.

I made a sandbox forked from the one linked above to demonstrate this: https://codesandbox.io/s/react-date-pickers-forked-5j5zg4?file=/src/App.js

Repoduction Steps

  1. Click the input to open the calendar
  2. Click the manual state change button
  3. See the input value changes, the calendar frame doesn't

Additionally, an oddity I've found:

  1. close the calendar
  2. open it again, and click the manual state change button
  3. You'll see it changed the frame, but consecutive clicks behave as they did from steps 1-3.
  4. Repeat 4-6

Edit:
Thinking it was maybe the custom container causing an issue, I made another sandbox without one and the issue still (kind of) persisted. The first few state changes work, then after 2-3 the calendar fails to update the frame.

@tabuckner
Copy link

tabuckner commented Feb 8, 2023

I've also run into a similar issue while using customInput prop wherein changing the state value assigned to selected does move the "cursor" however does not change the currently displayed month/year to "focus" the new stateful date value.

Here's a quick screencap showing the issue for my specific implementation:
Kapture 2023-02-08 at 16 00 57

Interestingly enough, when replicating a similar setup on the playground, everything
Kapture 2023-02-08 at 16 02 30
seems to work as expected:

Clearly, this is an issue specific to my implementation, but it's not clear to me why. Any guidance here would be helpful.

EDIT
Now I'm wondering if maybe it has something to do with ExampleCustomInput being declared within the same closure. I think that's generally a no-no in React-world. Maybe it's hiding a problem?

EDIT 2
Set up a minimally reproducible repo and proved that it's not related to having the component provided to customInput declared within the same closure that implements DatePicker. It does however seem that the library expects a specific interface for the component provided to customInput.
Check out the stackblitz

@vladhelios
Copy link

@tabuckner any updates? My custom input also doesn't update calendar value on manual input

@Raja-Kadali-FW
Copy link

same here

@hazimalperata
Copy link

When I was doing the date range picker with custom selectable ranges only used one DatePicker, I faced the same issue. Also, I made a CustomInput(docs) and CustomContainer(docs) for my DatePicker. Then, I used these for handling open state.

I hope this can be useful for you. For calendar update you can give the key based on startDate to DatePicker (like key={startDate.toString()}) but with this way you will lost shouldCloseOnSelect prop on DatePicker. After the giving key, you should write your own open state controller for DatePicker. For example:
const [isCalendarOpen, setIsCalendarOpen] = useState(false);

<DatePicker
    key={`datePicker_${startDate.toString()}`}
    onInputClick={() => setIsCalendarOpen(true)}
    onCalendarOpen={() => setIsCalendarOpen(true)}
    onCalendarClose={() => setIsCalendarOpen(false)}
    onClickOutside={() => setIsCalendarOpen(false)}
    open={isCalendarOpen}
    focusSelectedMonth
    .
    .
    .
  />

If you want that picker to close when the end date selected, you need to change onChange prop also. For example for my range change I did this const:

  const onChange = (dates: [Date | null, Date | null]) => {
    const [start, end] = dates;
    setStartDate(start as Date);
    setEndDate(end as Date);
    if (end) {
      setIsCalendarOpen(false);
    }
  };

The if statement did the same thing shouldCloseOnSelect prop. Also, you can do the same thing for custom selectable ranges. You need to setIsCalendarOpen(false) after the setDate.

I didn't try to use this handling on input or 2 different DatePicker components but at least worth to try.

@developerjhp
Copy link

developerjhp commented Apr 29, 2024

Here is the solution

I didn't want to resolve this issue in such a complex manner, but it seems like the only way, so I'm sharing it with you.

To change the calendar view, you must use the changeMonth and changeYear functions available in renderCustomHeader. To convert to a custom range in the CalendarContainer, these two functions need to be stored using a ref and then passed to CalendarContainer as props for use.
It's important to note that the parameters for changeMonth and changeYear are month or monthYear, not dates.
For example, to move to the previous month, you would execute changeMonth(new Date().getMonth() - 1).

// DatePicker.tsx

import { useRef } from "react";

function DatePicker() {
  const changeMonthRef = useRef(null);
  const changeYearRef = useRef(null);

  return (
    <ReactDatePicker
      renderCustomHeader={({ changeMonth, changeYear, ...otherProps }) => {
        // Store function in ref
        changeMonthRef.current = changeMonth;
        changeYearRef.current = changeYear;
        return (
          <StartEndDatePickerCustomHeader
            changeMonth={changeMonth}
            changeYear={changeYear}
            {...otherProps}
          />
        );
      }}
      calendarContainer={(props) => (
        <CalendarContainer changeMonth={changeMonthRef.current} {...props} />
      )}
    />
  );
}

// calendarContainer.tsx
   .....
   ...
   .
   
  const todayDateTime = new Date(
    getUserLocationTime().setHours(0, 0, 0, 0)
  );
  const thisMonthFirstDate = new Date(
    todayDateTime.getFullYear(),
    todayDateTime.getMonth(),
    1
  );
  const lastMonthFirstDate = new Date(
    todayDateTime.getFullYear(),
    todayDateTime.getMonth() - 1,
    1
  );
  const lastMonthLastDate = new Date(
    todayDateTime.getFullYear(),
    todayDateTime.getMonth(),
    0
  );
   
  function onMoveToTodayButtonClick() {
      onChangeDateTimeHandler(.... ) // change date function in here
      changeMonth(todayDateTime.getMonth());
      changeYear(todayDateTime.getFullYear());
   }
   function onMoveToLastMonthButtonClick() {
    onChangeDateTimeHandler(.... ) // change date function in here
    changeMonth(lastMonthLastDate.getMonth());
    changeYear(lastMonthLastDate.getFullYear());
  }
  function onMoveToThisMonthButtonClick() {
    onChangeDateTimeHandler(.... ) // change date function in here
    changeMonth(todayDateTime.getMonth());
    changeYear(todayDateTime.getFullYear());
  }

@Boncom99
Copy link

Boncom99 commented Jul 8, 2024

Are there any updates on this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants