React-dates: Uncaught TypeError: modifiers.has is not a function

Created on 5 Jun 2018  ·  22Comments  ·  Source: airbnb/react-dates

I get this error when click next month on DateRangePicker,

Uncaught TypeError: modifiers.has is not a function
at getCalendarDaySettings (getCalendarDaySettings.js?01ee:25)

bug

Most helpful comment

Hey all,

We ran into this one as well and it boiled down to a deepmerge dependency (repo).

In our app we're using [email protected] (latest).
However,
react-dates -> react-with-styles -> react-with-direction -> [email protected]

This causes some conflict which results in the .has() error outlined above. Seems as though the older version of deepmerge can handle Sets, but the newest version cannot. Downgrading to [email protected] on our end resolved this issue for us. Odd dependency problem, though...

All 22 comments

@thinhdd88 what version of react-dates are you using?

Also, are you using the airbnb-js-shims packages to polyfill the Set object?

Hello!

I get the same issue here.
Here is my stack:

[email protected] (Chromium 61.0.3163.100)
[email protected]

[email protected]
[email protected]
[email protected]
[email protected]

The DateRangePicker is called with the following props:

const datePickerProps = {
      displayFormat: 'YYYY/MM/DD',
      showDefaultInputIcon: true,
      startDate, // Moment
      endDate, // Moment
      startDateId: 'startDate',
      endDateId: 'endDate',
      onDatesChange: this.handleDatesChange,
      focusedInput: this.state.calendarFocused,
      onFocusChange: this.handleFocusChange,
      isOutsideRange: () => false,
    };

No polyfill used, and I'd rather not have to include extra dependencies if I can rely on babel already. .babelrc:

{
  "presets": [
    ["env", {
      "targets": { "node": 7 },
      "useBuiltIns": true
    }],
    "stage-0",
    "react"
  ]
  ...
}

Error stack trace:

[2018-06-24T13:15:39.964Z] : renderer::components::decorators::ErrorBoundary : error : ErrorBoundary has catched an error

 TypeError: r.has is not a function
    at t.default (getCalendarDaySettings.js:25)
    at ProxyComponent.o.value (CalendarDay.js:225)
    at ProxyComponent.w (createClassProxy.js:93)
    at finishClassComponent (react-dom.development.js:7873)
    at updateClassComponent (react-dom.development.js:7850)
    at beginWork (react-dom.development.js:8225)
    at performUnitOfWork (react-dom.development.js:10224)
    at workLoop (react-dom.development.js:10288)
    at HTMLUnknownElement.callCallback (react-dom.development.js:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
    at invokeGuardedCallback (react-dom.development.js:438)
    at renderRoot (react-dom.development.js:10366)
    at performWorkOnRoot (react-dom.development.js:11014)
    at performWork (react-dom.development.js:10967)
    at requestWork (react-dom.development.js:10878)
    at scheduleWorkImpl (react-dom.development.js:10732)

Highlighted code in the sourcemaps:

getCalendarDaySettings.js

function getCalendarDaySettings(day, ariaLabelFormat, daySize, modifiers, phrases) {
  var chooseAvailableDate = phrases.chooseAvailableDate,
      dateIsUnavailable = phrases.dateIsUnavailable,
      dateIsSelected = phrases.dateIsSelected;


  var daySizeStyles = {
    width: daySize,
    height: daySize - 1
  };

  var useDefaultCursor = modifiers.has('blocked-minimum-nights') || modifiers.has('blocked-calendar') || modifiers.has('blocked-out-of-range');

  var selected = modifiers.has('selected') || modifiers.has('selected-start') || modifiers.has('selected-end');

  var hoveredSpan = !selected && (modifiers.has('hovered-span') || modifiers.has('after-hovered-start'));

  var isOutsideRange = modifiers.has('blocked-out-of-range');

  var formattedDate = { date: day.format(ariaLabelFormat) };

  var ariaLabel = (0, _getPhrase2['default'])(chooseAvailableDate, formattedDate);
  if (modifiers.has(_constants.BLOCKED_MODIFIER)) {
    ariaLabel = (0, _getPhrase2['default'])(dateIsUnavailable, formattedDate);
  } else if (selected) {
    ariaLabel = (0, _getPhrase2['default'])(dateIsSelected, formattedDate);
  }

  return {
    daySizeStyles: daySizeStyles,
    useDefaultCursor: useDefaultCursor,
    selected: selected,
    hoveredSpan: hoveredSpan,
    isOutsideRange: isOutsideRange,
    ariaLabel: ariaLabel
  };
}

Let me know if you need more info to solve this issue. I'll check if I can find a workaround somehow.

EDIT: Issue is reproductible across versions [email protected], [email protected], [email protected], [email protected], but is not present in version [email protected]. I'll be switching to that version for the time being.

Which line is the one with “r.has”? There’s a bunch of modifiers.has calls in that function, so I’d expect it to fail much sooner than line 25 if “has” wasn’t a function :-/

The error occurs on the first modifiers.has and the modifiers object is an empty object rather than a Set as expected

Are you getting any propType warnings? CalendarDay requires an instanceof Set

None, the error only appears when clicking on the button. No other warning signs beforehand

When debugging the object received by the function is always a Set, up until that point

Hmm - CalendarMonth take an object instead of a Set or a Map, and passes it’s values on - https://github.com/airbnb/react-dates/blob/2081bd8f05ce9bc289b27a7e2893e3d7133197fa/src/components/CalendarMonth.jsx#L225 - @majapw, i think that propType should be objectOf(instanceOf(Set)), at least (probably on calendar month grid as well).

I’m mobile atm so i can’t trace it further, but it seems likely that modifiers sometimes being an object in the repo and sometimes a Set might be related.

Hey all,

We ran into this one as well and it boiled down to a deepmerge dependency (repo).

In our app we're using [email protected] (latest).
However,
react-dates -> react-with-styles -> react-with-direction -> [email protected]

This causes some conflict which results in the .has() error outlined above. Seems as though the older version of deepmerge can handle Sets, but the newest version cannot. Downgrading to [email protected] on our end resolved this issue for us. Odd dependency problem, though...

is this issue fixed already

Like @philippefutureboy I also see that at some point CalendarDay gets passed an object as modifiers which leads to the crash.

image

I temporarily fixed it by using this:

<SingleDatePicker
  renderCalendarDay={({ modifiers, ...props }) => {
    return <CalendarDay modifiers={safeModifiers(modifiers)} {...props} />
  }}
/>
const safeModifiers = modifiers => {
  return isSet(modifiers) ? modifiers : new Set()
}

I hope this maybe helps someone else running into the same issue.
Since the deepmerge topic described above didn't fix it for me.

As always, very thankful for the work put into this awesome library.

@majapw

Is it possible Set is being polyfilled differently between airbnb and other users of the libarary? I'm getting this same error; airbnb-js-shims is in my node_modules and I'm on "react-dates": "^18.3.1" and "react": "^16.5.1".

Our project uses babel and includes @babel/preset-env and @babel/react, babel has its own polyfill, Set seems to be covered there.

If it's a matter of the polyfill, it would seem the fix would have to be in the library where those inconsistencies could be managed, rather than requiring all users to have the same polyfills. Would this be a correct assessment?

@codylawson there's really only two common Set polyfills out there - the one in es6-shim (in airbnb-js-shims and the one in core-js (in babel-polyfill). Both have a has function.

@ljharb that makes sense, just trying to find differences in your storybook from our project 😄.

Would handling undefined modifiers still be something the library should handle? I can make a pr if it's as simple as applying the logic from @klujanrosas's workaround into the CalendarDay.

As you can see from the screenshot above, modifiers isn't undefined, it's an object, that has no has function.

I'm interested in a fix, but not a workaround :-)

Same error! This is big. Simply changing the month is causing this error for me.

@divyanthj any info to help reproduce would be appreciated.

+1

formik has a [email protected] dependency and I don't want to fork the repo just to use a different version like @icd2k3 's solution, used @klujanrosas 's workaround instead but it feels wrong.

@Parader similarly, any info to help reproduce would be appreciated :-)

@Parader similarly, any info to help reproduce would be appreciated :-)

@ljharb I wasn't able to reproduce on a create-react-app boilerplate so I guess it has to do with the way I use babel-ployfill. It's probably not a react-dates problem, thanks for replying

I have been able to debug this issue in a setup where [email protected] was being used. It boiled down to react-with-styles running defaultProps through deepmerge before assigning the result to WithStyles.defaultProps and for whatever reason the version of deepmerge that was used would turn Sets into an empty JavaScript object. Updating react-with-styles to 3.2.3 fixed the issue (well, strictly speaking, the fix is in 3.2.2 too). I believe bumping react-with-styles dependency to ^3.2.3 would be sufficient to close this issue - although new installations wouldn't be affected by this because it should pull down the latest semver-compatible version of react-with-styles from npm.

Was this page helpful?
0 / 5 - 0 ratings