React-day-picker: Cannot read property 'focus' of null

Created on 6 Jun 2017  ·  11Comments  ·  Source: gpbl/react-day-picker

I'm using this library with a muicss input component that I pass into DatePickerInput. Everything works fine when clicking out of the calendar, but when I select a date I get the error "Cannot read property 'focus' of null." I believe it is because muicss uses a div with an input inside. I can make the error go away if I pass a null to the onBlur event, like so:

<DayPickerInput required={true}
value={this.state.start_date}
component={props =>
    <Input {...props}
        onBlur={null}
        label='Start Date'
        floatingLabel={true} />
}
onDayChange={this.startDateChanged}
format={this.format} />

But now the calendar doesn't go away when clicking outside of it. Any ideas on how to solve this?

help wanted

Most helpful comment

The problem is when passing the Input component like this will not work:
component={(props) => <Input {...props}/> }
What will work is passing it like this
component={ Input }.
Now this is not really helpful as most of our Input components are custom made and we need to more props.
What do you think is the problem here @gpbl ?

I looked more into the differences between both scenarios deeply, and it looks like the refs are not getting forwarded to the child component in this case the the custom Input component that are being used this way component={(props) => <Input {...props}/> }

All 11 comments

I had the same issue just passing a plain old input component

The component prop should receive the component class, thus:

<DayPickerInput 
    required={true}
    value={this.state.start_date}
    label='Start Date'
    floatingLabel={true}
    component={Input}
    onDayChange={this.startDateChanged}
    format={this.format} 
/>

should work as expected. Please report back if not, thanks!

@gpbl That did not work for me, same error as before.

@gpbl I can also confirm what @Yustynn said, if I pass in just a plain input inside a class or functional component, I get the same error. It appears that the custom component is broken.
This is what I've tried:

const MyInput = (props) => {
    return <input {...props} name='bob' />
}
...
render() {
    return <DayPickerInput required={true}
        value={this.state.start_date}
        component={MyInput}
        onDayChange={this.startDateChanged}
        format={this.format} />
}

Edit: removing this on DatePickerInput fixed the problem for me:

// Force input's focus if blur event was caused
// by clicking inside the overlay
if (this.clickedInside) {
  this.input.focus();
}

@tmonte to work properly with a custom input component, the input component must be compatible with the standard html input: this means it should support onChange, onFocus, onKeyUp, onClick and onBlur and the focus method. Thus, this won't work because it has no focus method on it:

const MyInput = (props) => {
    return <input {...props} name='bob' />
}

This will work instead:

class MyInput extends React.Component {
    focus = () => {
        this.input.focus();
    }
    render() {
        return <input ref={el => this.input = el} {...this.props} />;
    }
}

so either you wrap the muicss input component into a component supporting focus (like the above) or ask muicss to add the focus method to the component.

This should be clarified better in the docs... wondering if it should be implemented in another way :)

Managing interaction with input and overlays is a bit complicated for usability reasons. I'll keep this issue open until I don't address the case in the docs.

Hello, I am still running into this issue and would greatly appreciate some help. I tried the solutions above and my code looks like this:

import React, { PropTypes } from 'react';
import moment from 'moment';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import debounce from 'lodash/debounce';
import 'react-day-picker/lib/style.css';

import FilterInput from '../FilterPanel/FilterInput';
import TextInput from '../common/TextInput';
import { isValidDate } from '../../utils/date-helpers';

const dayFormat = 'MM/DD/YYYY';

class DateInput extends React.Component {
  focus = () => {
    this.input.focus();
  }
  render() {
    return (
      <TextInput
        ref={(el) => (this.input = el)}
        {...this.props}
      />
    );
  }
}

class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      selectedDay: '',
    };
  }

  componentWillMount() {
    this.handleDateManualInput = debounce((evt) => {
      const { value } = evt.target;
      const date = moment(evt.target.value);
      if (isValidDate(value) && date.get('year') > 2010) {
        const formattedDate = date.format('L');
        this.setStateFormattedDate(formattedDate);
        this.dispatchNewDate(formattedDate);
      }
    }, 500);
  }

  setStateFormattedDate = (selectedDay) => this.setState({ selectedDay })

  dispatchNewDate = (date) => this.props.onChangeDate({ type: this.props.type, date })

  handleDayChange = (date) => {
    if (date) {
      const formattedDate = date.format('L');
      this.setStateFormattedDate(formattedDate);
      this.dispatchNewDate(formattedDate);
    }
  }

  render() {
    const { selectedDay } = this.state;
    const formattedDay = selectedDay ? moment(selectedDay).format(dayFormat) : '';
    return (
      <FilterInput>
        <DayPickerInput
          component={DateInput}
          label={this.props.label}
          value={formattedDay}
          onDayChange={this.handleDayChange}
          onChange={this.handleDateManualInput}
          format={dayFormat}
          placeholder={this.props.placeholder}
        />
      </FilterInput>
    );
  }
}

Main.propTypes = {
  onChangeDate: PropTypes.func.isRequired,
  type: PropTypes.string.isRequired,
  label: PropTypes.string.isRequired,
  placeholder: PropTypes.string,
};

export default Main;

Despite wrapping my input in something that clearly handles focus, it still get the typeerror. In the source code, it looks like _this is set to null no matter what. Is that possibly the issue?

@mperitz could you replicate your issue in a code sandbox? e.g. start forking this: https://codesandbox.io/s/XDAE3x0W8 thanks!

The problem is when passing the Input component like this will not work:
component={(props) => <Input {...props}/> }
What will work is passing it like this
component={ Input }.
Now this is not really helpful as most of our Input components are custom made and we need to more props.
What do you think is the problem here @gpbl ?

I looked more into the differences between both scenarios deeply, and it looks like the refs are not getting forwarded to the child component in this case the the custom Input component that are being used this way component={(props) => <Input {...props}/> }

What do you think is the problem here @gpbl ?

Me 🤦‍♂️ :)

That part is clearly broken. We should look at how react-select implements custom components (I liked that pattern) and rewrite that thing.

Thing has been rewritten in #942 :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mcapodici picture mcapodici  ·  3Comments

kostiantyn-solianyk picture kostiantyn-solianyk  ·  4Comments

michaelgriffithus picture michaelgriffithus  ·  5Comments

olimination picture olimination  ·  4Comments

vulcanoidlogic picture vulcanoidlogic  ·  6Comments