Reputation: 77
all...I'm using the 'react-day-picker' component to choose a range of dates via two inputs.
I started by using, verbatim, the example on this page: http://react-day-picker.js.org/examples/input-from-to. The only alterations I made was the add console.log(this.state)
to the handleFromChange
and handleToChange
methods.
The component seems to work at first glance, but when I console.log the state, I found that the "to" state is only being updated the second time a "to" date is selected in the picker. Selecting a "to" date the first time returns "undefined."
Looking at this code, is there anything that jumps out as incorrect? Again, this code was provided by the creator of the component. I'm trying to figure out if its a bug with the component, a bug with the example code, or some other problem.
Thanks!
For convenience, here's the code I'm using:
import React from 'react';
import moment from 'moment';
import Helmet from 'react-helmet';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import 'react-day-picker/lib/style.css';
import { formatDate, parseDate } from 'react-day-picker/moment';
export default class Example extends React.Component {
constructor(props) {
super(props);
this.handleFromChange = this.handleFromChange.bind(this);
this.handleToChange = this.handleToChange.bind(this);
this.state = {
from: undefined,
to: undefined,
};
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
focusTo() {
// Focus to `to` field. A timeout is required here because the overlays
// already set timeouts to work well with input fields
this.timeout = setTimeout(() => this.to.getInput().focus(), 0);
}
showFromMonth() {
const { from, to } = this.state;
if (!from) {
return;
}
if (moment(to).diff(moment(from), 'months') < 2) {
this.to.getDayPicker().showMonth(from);
}
}
handleFromChange(from) {
// Change the from date and focus the "to" input field
this.setState({ from }, () => {
if (!this.state.to) {
this.focusTo();
}
});
}
handleToChange(to) {
this.setState({ to }, this.showFromMonth);
}
render() {
const { from, to } = this.state;
const modifiers = { start: from, end: to };
return (
<div className="InputFromTo">
<DayPickerInput
value={from}
placeholder="From"
format="LL"
formatDate={formatDate}
parseDate={parseDate}
dayPickerProps={{
selectedDays: [from, { from, to }],
disabledDays: { after: to },
toMonth: to,
modifiers,
numberOfMonths: 2,
}}
onDayChange={this.handleFromChange}
/>{' '}
—{' '}
<span className="InputFromTo-to">
<DayPickerInput
ref={el => (this.to = el)}
value={to}
placeholder="To"
format="LL"
formatDate={formatDate}
parseDate={parseDate}
dayPickerProps={{
selectedDays: [from, { from, to }],
disabledDays: { before: from },
modifiers,
month: from,
fromMonth: from,
numberOfMonths: 2,
}}
onDayChange={this.handleToChange}
/>
</span>
<Helmet>
<style>{`
.InputFromTo .DayPicker-Day--selected:not(.DayPicker-Day--start):not(.DayPicker-Day--end):not(.DayPicker-Day--outside) {
background-color: #f0f8ff !important;
color: #4a90e2;
}
.InputFromTo .DayPicker-Day {
border-radius: 0 !important;
}
.InputFromTo .DayPicker-Day--start {
border-top-left-radius: 50% !important;
border-bottom-left-radius: 50% !important;
}
.InputFromTo .DayPicker-Day--end {
border-top-right-radius: 50% !important;
border-bottom-right-radius: 50% !important;
}
.InputFromTo .DayPickerInput-Overlay {
width: 550px;
}
.InputFromTo-to .DayPickerInput-Overlay {
margin-left: -198px;
}
`}</style>
</Helmet>
</div>
);
}
}
Upvotes: 1
Views: 2983
Reputation: 3433
I checked your code. It looks like it receives proper value in the state for both the two value To and From. Maybe you have console.log(this.state) at the wrong place.
Let me tell you that setState method is asynchronous so you must be getting the wrong values.
I've added a console.log statement at appropriate state to show you that the value is reflected right. Have a look at below code
import React from 'react';
import moment from 'moment';
import Helmet from 'react-helmet';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import 'react-day-picker/lib/style.css';
import { formatDate, parseDate } from 'react-day-picker/moment';
export default class Example extends React.Component {
constructor(props) {
super(props);
this.handleFromChange = this.handleFromChange.bind(this);
this.handleToChange = this.handleToChange.bind(this);
this.state = {
from: undefined,
to: undefined,
};
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
focusTo() {
// Focus to `to` field. A timeout is required here because the overlays
// already set timeouts to work well with input fields
this.timeout = setTimeout(() => this.to.getInput().focus(), 0);
}
showFromMonth() {
console.log("value from the state",this.state);
const { from, to } = this.state;
if (!from) {
return;
}
if (moment(to).diff(moment(from), 'months') < 2) {
this.to.getDayPicker().showMonth(from);
}
}
handleFromChange(from) {
console.log("New From value", from);
// Change the from date and focus the "to" input field
this.setState({ from }, () => {
console.log("value from the state",this.state);
if (!this.state.to) {
this.focusTo();
}
});
}
handleToChange(to) {
console.log("New To value", to);
this.setState({ to }, this.showFromMonth);
}
render() {
const { from, to } = this.state;
const modifiers = { start: from, end: to };
return (
<div className="InputFromTo">
<DayPickerInput
value={from}
placeholder="From"
format="LL"
formatDate={formatDate}
parseDate={parseDate}
dayPickerProps={{
selectedDays: [from, { from, to }],
disabledDays: { after: to },
toMonth: to,
modifiers,
numberOfMonths: 2,
}}
onDayChange={this.handleFromChange}
/>{' '}
—{' '}
<span className="InputFromTo-to">
<DayPickerInput
ref={el => (this.to = el)}
value={to}
placeholder="To"
format="LL"
formatDate={formatDate}
parseDate={parseDate}
dayPickerProps={{
selectedDays: [from, { from, to }],
disabledDays: { before: from },
modifiers,
month: from,
fromMonth: from,
numberOfMonths: 2,
}}
onDayChange={this.handleToChange}
/>
</span>
<Helmet>
<style>{`
.InputFromTo .DayPicker-Day--selected:not(.DayPicker-Day--start):not(.DayPicker-Day--end):not(.DayPicker-Day--outside) {
background-color: #f0f8ff !important;
color: #4a90e2;
}
.InputFromTo .DayPicker-Day {
border-radius: 0 !important;
}
.InputFromTo .DayPicker-Day--start {
border-top-left-radius: 50% !important;
border-bottom-left-radius: 50% !important;
}
.InputFromTo .DayPicker-Day--end {
border-top-right-radius: 50% !important;
border-bottom-right-radius: 50% !important;
}
.InputFromTo .DayPickerInput-Overlay {
width: 550px;
}
.InputFromTo-to .DayPickerInput-Overlay {
margin-left: -198px;
}
`}</style>
</Helmet>
</div>
);
}
}
Upvotes: 1