react-infinite-calendar icon indicating copy to clipboard operation
react-infinite-calendar copied to clipboard

Scroll resets to first selected element in a multipleDates calendar when state is updated

Open davidjmstewart opened this issue 4 years ago • 3 comments

When using multiple dates functionality, the calendar resets to the zoom to focus on the first selected date on a re-render.

I think most users would expect the scroll to remain unchanged. Is there a way to use the InfiniteCalendar API to avoid this?

See this CodeSandbox

ezgif-3-f09e75df0763

Full code

import React, { useState } from "react";
import "./styles.css";
import InfiniteCalendar, {
  Calendar,
  defaultMultipleDateInterpolation,
  withMultipleDates,
} from 'react-infinite-calendar';
import 'react-infinite-calendar/styles.css'; // only needs to be imported once

export default function App() {

  const [selectedCalendarDates, setSelectedCalendarDates] = useState([]);

  const arrayRemove = (arr, value) => {
    return arr.filter(function (ele) {
      return ele != value;
    });
  }

  // Credit: Mayura Wijewickrama https://stackoverflow.com/questions/45504601/react-infinite-calendar-set-the-date
  const updateSelectedCalendarDates = (date) => {
    var converted =  date.toLocaleString('default', { weekday: 'short' }) 
                  + ' ' + date.toLocaleString('default', { month: 'short' }) 
                  + ' ' + date.getDate() + ' ' +date.getFullYear() + ' 00:00:00';

    if (!selectedCalendarDates.includes(converted)) {
        setSelectedCalendarDates([...selectedCalendarDates, converted]);
    } else {
        var result = arrayRemove(selectedCalendarDates, converted);
        setSelectedCalendarDates(result);
    }
  }

    return (
        <InfiniteCalendar
        Component={withMultipleDates(Calendar)}
        selected={selectedCalendarDates}
        width={'100%'}
        height={600}
        interpolateSelection={defaultMultipleDateInterpolation}
        onSelect={updateSelectedCalendarDates}
        minDate={new Date()} // Minimum selectable date is today
        min={new Date()} // Minimum date the calendar can be scrolled to is today
    />
  );
}

davidjmstewart avatar Dec 01 '20 05:12 davidjmstewart

This is a problem with the height property, quick fix: remove the height prop

<InfiniteCalendar
        Component={withMultipleDates(Calendar)}
        selected={selectedCalendarDates}
        width={'100%'}
        interpolateSelection={defaultMultipleDateInterpolation}
        onSelect={updateSelectedCalendarDates}
        minDate={new Date()} // Minimum selectable date is today
        min={new Date()} // Minimum date the calendar can be scrolled to is today
    />

fteichma avatar Dec 18 '20 22:12 fteichma

I fixed it by moving the component declaration out of the building method as follows:

const IntiniteCalendarComponent = withMultipleDates(Calendar);

export default () => {
 ...
  <InfiniteCalendar
              Component={IntiniteCalendarComponent}
              .../>

brooth avatar Oct 14 '21 10:10 brooth

Did you guys solve this? I tracked it down to the onSelect={updateSelectedCalendarDates}. Since it updates the state it then rerenders the component. I could understand that if you have the state in selected. But I tried with different statets and it still rerenders. Any update or fix?

ludvigaldrin avatar Aug 25 '22 06:08 ludvigaldrin