UNPKG

react-select-module

Version:
157 lines (153 loc) 4.57 kB
import React, { Component } from 'react'; import { handleInputChange } from './utils'; import manageState from './stateManager'; import Select from './Select'; export const defaultProps = { cacheOptions: false, defaultOptions: false, filterOption: null, isLoading: false, }; export const makeAsyncSelect = SelectComponent => class Async extends Component { static defaultProps = defaultProps; select; lastRequest; mounted = false; optionsCache = {}; constructor(props) { super(); this.state = { defaultOptions: Array.isArray(props.defaultOptions) ? props.defaultOptions : undefined, inputValue: typeof props.inputValue !== 'undefined' ? props.inputValue : '', isLoading: props.defaultOptions === true, loadedOptions: [], passEmptyOptions: false, }; } componentDidMount() { this.mounted = true; const { defaultOptions } = this.props; const { inputValue } = this.state; if (defaultOptions === true) { this.loadOptions(inputValue, options => { if (!this.mounted) return; const isLoading = !!this.lastRequest; this.setState({ defaultOptions: options || [], isLoading }); }); } } UNSAFE_componentWillReceiveProps(nextProps) { // if the cacheOptions prop changes, clear the cache if (nextProps.cacheOptions !== this.props.cacheOptions) { this.optionsCache = {}; } if (nextProps.defaultOptions !== this.props.defaultOptions) { this.setState({ defaultOptions: Array.isArray(nextProps.defaultOptions) ? nextProps.defaultOptions : undefined, }); } } componentWillUnmount() { this.mounted = false; } focus() { this.select.focus(); } blur() { this.select.blur(); } loadOptions(inputValue, callback) { const { loadOptions } = this.props; if (!loadOptions) return callback(); const loader = loadOptions(inputValue, callback); if (loader && typeof loader.then === 'function') { loader.then(callback, () => callback()); } } handleInputChange = (newValue, actionMeta) => { const { cacheOptions, onInputChange } = this.props; // TODO const inputValue = handleInputChange(newValue, actionMeta, onInputChange); if (!inputValue) { delete this.lastRequest; this.setState({ inputValue: '', loadedInputValue: '', loadedOptions: [], isLoading: false, passEmptyOptions: false, }); return; } if (cacheOptions && this.optionsCache[inputValue]) { this.setState({ inputValue, loadedInputValue: inputValue, loadedOptions: this.optionsCache[inputValue], isLoading: false, passEmptyOptions: false, }); } else { const request = (this.lastRequest = {}); this.setState( { inputValue, isLoading: true, passEmptyOptions: !this.state.loadedInputValue, }, () => { this.loadOptions(inputValue, options => { if (!this.mounted) return; if (options) { this.optionsCache[inputValue] = options; } if (request !== this.lastRequest) return; delete this.lastRequest; this.setState({ isLoading: false, loadedInputValue: inputValue, loadedOptions: options || [], passEmptyOptions: false, }); }); } ); } return inputValue; }; render() { const { loadOptions, isLoading: isLoadingProp, ...props } = this.props; const { defaultOptions, inputValue, isLoading, loadedInputValue, loadedOptions, passEmptyOptions, } = this.state; const options = passEmptyOptions ? [] : inputValue && loadedInputValue ? loadedOptions : defaultOptions || []; return ( <SelectComponent {...props} ref={ref => { this.select = ref; }} options={options} isLoading={isLoading || isLoadingProp} onInputChange={this.handleInputChange} /> ); } }; const SelectState = manageState(Select); export default makeAsyncSelect(SelectState);