简体   繁体   中英

Solved: React-day-picker Daypicker Input loses focus when using custom input component

The working sandbox is https://codesandbox.io/s/react-day-picker-base-h9fv6

I have been trying to implement a simple day picker input, where you can both enter the date in the input field and select in the picker.

The problem is that when I use a custom input, <DayPickerInput component ={CustomInput}.../> , the input loses focus when the picker is used. This does not happen without a custom input. In the docs it says

"If you want to keep the focus when the user picks a day, the component class must have a focus method."

However I am not sure how I should implement this.

If you need a custom component with a focus method, I think you need to use a class component, and refs :

class Input extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  focus() {
    this.inputRef.current.focus();
  }

  render() {
    return <input {...this.props} ref={this.inputRef}/>
  }
}

I use the MaskedInput component from " react-text-mask " library, and custom overlay component for 'Date Range picker with two inputs' from ' react-day-picker '.

Custom overlay and input:

const renderMaskedInput = (_props, _ref) => {
        return (
           <MaskedInput
             mask={getLocaleMask}
             showMask
             ref={_ref}
             type="text"
             render={(ref, inputProps) => <input ref={ref} {...inputProps} />}
             {..._props}
      />
    );};


<DayPickerInput
   component={_props => renderMaskedInput(_props, startInputRef)}
   overlayComponent={_props => (
      <Popper
        open={Boolean(startAnchorEl)}
        anchorEl={startAnchorEl}
        style={{ zIndex: 10000 }}
      >
        <div {..._props} className={customOverlayWrapper}>
          <div className={customOverlay}>{_props.children}</div>
        </div>
      </Popper>
    )}

My problem was in losing focus from the picker input when opening or clicking on the custom overlay , and the ' keepFocus ' prop is did not work with custom input. So it causes problems with closing overlay after clicking on backdrop , because the overlay is closing only by 'onBlur' of input.

Just hard-setting focus on the input by onClick or something else did not work. My solution is setting focus in useEffect after changing input ref when the custom overlay is opening, but it did not enough because the focus is losing after clicking on the overlay, so we just setting focus to input after 3 handlers of DayPicker : onFocus, onMonthChange, onCaptionChange (see codesandbox example).

And using Popper as a custom overlay for DayPickerInput solves a problem with rendering overlay in a free area at the screen (auto-positioning of overlay). Also, Popper works with Portal and it solves many problems with rendering overlay.

Full code : https://codesandbox.io/s/optimistic-glitter-c77gb

Short version :

    const focusStartInput = () => {
      startInputRef.current.inputElement.focus();
    }
    
    useEffect(() => {
    // used because 'keepFocus' prop from the library does not work with the custom 
    //   overlay or with the react-text-mask input
    
    if (startAnchorEl) {
      // if the start picker overlay is open
      focusStartInput(); // input loses focus after overlay opening,
                         // so just reset focus
    }

    if (endAnchorEl) {
      // if the end picker overlay is open
      focusEndInput(); // input loses focus after overlay opening, so just reset focus
    }
  }, [startAnchorEl, endAnchorEl]);

<DayPickerInput
   dayPickerProps={{ 
     onMonthChange: focusStartInput,
     onFocus: focusStartInput,
     onCaptionClick: focusStartInput,
   }}
   

There is a problem with a solution from the main question . His input loses focus if we clicking not on the day in date picker (on the caption, month navigation, or somewhere else). My code helps to solve it .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM