Skip to content

Commit

Permalink
fix bug infinite loop
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtran committed Aug 2, 2020
1 parent 0d9b118 commit f64a928
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 60 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-google-flight-datepicker",
"version": "0.1.8",
"version": "0.1.10",
"description": "An ReactJS implementation for Google Flight date-picker by JSLancer team",
"author": "David Tran, Leo Phan",
"license": "MIT",
Expand Down
67 changes: 44 additions & 23 deletions src/lib/components/DatePicker/RangeDatePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, {
import PropTypes from 'prop-types';
import cx from 'classnames';
import dayjs from 'dayjs';

import { debounce } from '../../helpers';
import './styles.scss';
import DateInputGroup from './DateInputGroup';
import DialogWrapper from './DialogWrapper';
Expand All @@ -31,6 +31,8 @@ const RangeDatePicker = ({
const [inputFocus, setInputFocus] = useState('to');
const [fromDate, setFromDate] = useState();
const [toDate, setToDate] = useState();
const fromDateRef = useRef();
const toDateRef = useRef();
const [hoverDate, setHoverDate] = useState();
const [isFirstTime, setIsFirstTime] = useState(false);
const [isMobile, setIsMobile] = useState(false);
Expand Down Expand Up @@ -68,21 +70,40 @@ const RangeDatePicker = ({
}, []);

useEffect(() => {
if (startDate) {
setFromDate(dayjs(startDate));
}
if (endDate) {
setToDate(dayjs(endDate));
}
}, [startDate, endDate]);
const _startDateJs = startDate ? dayjs(startDate) : null;
fromDateRef.current = _startDateJs;
updateFromDate(_startDateJs, false);
}, [startDate]);

useEffect(() => {
if (isFirstTime) {
const startDate = fromDate ? dayjs(fromDate) : null;
const endDate = toDate ? dayjs(toDate) : null;
onChange(startDate, endDate);
const _endDateJs = endDate ? dayjs(endDate) : null;
toDateRef.current = _endDateJs;
updateToDate(_endDateJs, false);
}, [endDate]);

const debounceNotifyChange = debounce(notifyChange, 20);

function notifyChange() {
const _startDate = fromDateRef.current ? fromDateRef.current.toDate() : null;
const _endDate = toDateRef.current ? toDateRef.current.toDate() : null;
onChange(_startDate, _endDate);
}

function updateFromDate(dateValue, shouldNotifyChange = false) {
setFromDate(dateValue);
fromDateRef.current = dateValue;
if (shouldNotifyChange) {
debounceNotifyChange();
}
}

function updateToDate(dateValue, shouldNotifyChange = false) {
setToDate(dateValue);
toDateRef.current = dateValue;
if (shouldNotifyChange) {
debounceNotifyChange();
}
}, [fromDate, toDate]);
}

useEffect(() => {
if (isFirstTime) {
Expand Down Expand Up @@ -114,20 +135,20 @@ const RangeDatePicker = ({
function onSelectDate(date) {
if (inputFocus) {
if (inputFocus === 'from' || (fromDate && date.isBefore(fromDate, 'date'))) {
setFromDate(date);
updateFromDate(date, true);
if (toDate && date.isAfter(toDate, 'date')) {
setToDate(null);
updateToDate(null, true);
}
setInputFocus('to');
} else {
setToDate(date);
updateToDate(date, true);
setInputFocus(null);
}
} else {
setFromDate(date);
updateFromDate(date, true);
setInputFocus('to');
if (toDate && date.isAfter(toDate, 'date')) {
setToDate(null);
updateToDate(null, true);
}
}
}
Expand All @@ -138,9 +159,9 @@ const RangeDatePicker = ({

function handleReset() {
setInputFocus('from');
setFromDate(null);
setToDate(null);
setHoverDate(null);
updateFromDate(null, true);
updateToDate(null, true);
}

function handleChangeDate(value, input) {
Expand All @@ -150,13 +171,13 @@ const RangeDatePicker = ({

if (input === 'from') {
setInputFocus('from');
setFromDate(value);
updateFromDate(value, true);
if (value > toDate) {
setToDate(null);
updateToDate(null, true);
}
} else {
setInputFocus('to');
setToDate(value);
updateToDate(value, true);
}
}

Expand Down
15 changes: 2 additions & 13 deletions src/lib/components/DatePicker/SingleDatePicker.examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,11 @@ DatePicker examples:
###### SingleDatePicker

```js
import { SingleDatePicker } from 'react-google-flight-datepicker';
import { TestDatePicker } from 'react-google-flight-datepicker';

<div className="react-google-flight-datepicker">
<div className="date-picker-demo">
<SingleDatePicker
// startDatePlaceholder="My from date"
// onChange={(startDate, endDate) => console.log(startDate, endDate)}
// onFocus={(inputFocus) => console.log(inputFocus)}
startDate={new Date(2020, 7, 25)}
endDate={new Date('2020-10-25')}
// startWeekDay="sunday"
minDate={new Date(2019, 11, 10)}
maxDate={new Date('2020-11-25')}
dateFormat="DD/MM/YYYY"
// monthFormat="MMM --- YY"
/>
<TestDatePicker />
</div>
</div>
```
40 changes: 23 additions & 17 deletions src/lib/components/DatePicker/SingleDatePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, {
import PropTypes from 'prop-types';
import cx from 'classnames';
import dayjs from 'dayjs';

import { debounce } from '../../helpers';
import './styles.scss';
import DateInputGroup from './DateInputGroup';
import Dialog from './Dialog';
Expand All @@ -27,6 +27,7 @@ const SingleDatePicker = ({
const [isOpen, setIsOpen] = useState(false);
const containerRef = useRef(null);
const [fromDate, setFromDate] = useState();
const fromDateRef = useRef();
const [hoverDate, setHoverDate] = useState();
const [isFirstTime, setIsFirstTime] = useState(false);
const [isMobile, setIsMobile] = useState(false);
Expand All @@ -43,17 +44,31 @@ const SingleDatePicker = ({
handleResize();
if (typeof window !== 'undefined') {
window.addEventListener('resize', handleResize);

return () => window.removeEventListener('resize', handleResize);
}
}, []);

useEffect(() => {
if (startDate) {
setFromDate(dayjs(startDate));
}
const _startDateJs = startDate ? dayjs(startDate) : null;
fromDateRef.current = _startDateJs;
setFromDate(_startDateJs);
}, [startDate]);

const debounceNotifyChange = debounce(notifyChange, 20);

function notifyChange() {
const _startDate = fromDateRef.current ? fromDateRef.current.toDate() : null;
onChange(_startDate);
}

function updateFromDate(dateValue, shouldNotifyChange = false) {
setFromDate(dateValue);
fromDateRef.current = dateValue;
if (shouldNotifyChange) {
debounceNotifyChange();
}
}

function handleDocumentClick(e) {
if (
containerRef.current
Expand All @@ -67,21 +82,12 @@ const SingleDatePicker = ({
useEffect(() => {
setIsFirstTime(true);
if (startDate) {
setFromDate(dayjs(startDate));
updateFromDate(dayjs(startDate), false);
}

document.addEventListener('click', handleDocumentClick);

return () => document.removeEventListener('click', handleDocumentClick);
}, []);

useEffect(() => {
if (isFirstTime) {
const startDate = fromDate ? dayjs(fromDate) : null;
onChange(startDate);
}
}, [fromDate]);

function toggleDialog() {
setIsOpen(!isOpen);
}
Expand All @@ -100,15 +106,15 @@ const SingleDatePicker = ({
if ((minDate && dayjs(minDate).isAfter(date, 'date')) || (maxDate && dayjs(maxDate).isBefore(date, 'date'))) {
return;
}
setFromDate(date);
updateFromDate(date, true);
}

function onHoverDate(date) {
setHoverDate(date);
}

function handleReset() {
setFromDate(null);
updateFromDate(null, true);
setHoverDate(null);
}

Expand Down
14 changes: 8 additions & 6 deletions src/lib/components/DatePicker/TestDatePicker.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, { useEffect, useState } from 'react';
import RangeDatePicker from './RangeDatePicker';
import SingleDatePicker from './SingleDatePicker';
import dayjs from 'dayjs';

const TestDatePicker = () => {
const [startDate, setStartDate] = useState(null);
setTimeout(() => {
setStartDate(dayjs().add(3, 'day'));
}, 5000);
const [endDate, setEndDate] = useState(null);

return (
<RangeDatePicker
<SingleDatePicker
startDate={startDate}
onChange={() => {
console.log('change');
endDate={endDate}
onChange={(date1, date2) => {
setStartDate(date1);
setEndDate(date2);
}}
/>
);
Expand Down
28 changes: 28 additions & 0 deletions src/lib/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,31 @@ export function getWeekDay(startWeekDay) {

return arrWeekDay;
}

export function debounce(func, wait) {
let timeout;

// This is the function that is returned and will be executed many times
// We spread (...args) to capture any number of parameters we want to pass
return function executedFunction(...args) {

// The callback function to be executed after
// the debounce time has elapsed
const later = () => {
// null timeout to indicate the debounce ended
timeout = null;

// Execute the callback
func(...args);
};
// This will reset the waiting every function execution.
// This is the step that prevents the function from
// being executed because it will never reach the
// inside of the previous setTimeout
clearTimeout(timeout);

// Restart the debounce waiting period.
// setTimeout returns a truthy value (it differs in web vs Node)
timeout = setTimeout(later, wait);
};
};

0 comments on commit f64a928

Please sign in to comment.