Skip to content

Instantly share code, notes, and snippets.

@vonwao
Last active June 1, 2018 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vonwao/fd8bdedafa3c4b61ab24b7a5cc185b68 to your computer and use it in GitHub Desktop.
Save vonwao/fd8bdedafa3c4b61ab24b7a5cc185b68 to your computer and use it in GitHub Desktop.
import React from 'react';
import PropTypes from 'prop-types';
import debounce from 'lodash/debounce';
class OnChangeDebounce extends React.Component{
constructor(props){
super(props);
this.isValueSourceProps = this.props.hasOwnProperty(this.props.valueProperty);
this._createDebounceFunction(props);
this.state = {
value:this.props[this.props.valueProperty]||''
}
}
componentWillReceiveProps = (nextProps) => {
this.isValueSourceProps = nextProps.hasOwnProperty(nextProps.valueProperty);
// Check if the debounce function should be recreated
if(nextProps.wait !== this.props.wait || nextProps.waitOptions !== this.props.waitOptions){
this._createDebounceFunction(nextProps);
}
// Check if the displaying value is updated and the input isn't debouncing
// Redux will typically supply a value which is not inline with the current
// input value, but if not debouncing the value should be updated
if(nextProps.hasOwnProperty(this.props.valueProperty) && !this.state.debouncing){
this.setState({
value: nextProps[this.props.valueProperty]
});
}
};
_createDebounceFunction = (props) => {
this.onChangeDebounce = debounce(
(...args)=> {
this.setState({
debouncing:false
});
// Execute in promise so the ui thread can return
Promise.resolve().then(()=> this.props.onDebounce(this.props.getValueFromEvent(...args)))
}
,props.wait,props.waitOptions);
};
onChange = (...args) => {
this.setState({
value:this.props.getValueFromEvent(...args),
debouncing:true
});
this.onChangeDebounce(...args);
};
render(){
const {
as:As,
valueProperty,
onChangeProperty,
onDebounce,
getValueFromEvent,
wait,
waitOptions,
...props
} = this.props;
const value = !this.state.debouncing && this.isValueSourceProps ?
this.props[valueProperty]:
this.state.value;
return <As
{...props}
{...{
[valueProperty]: value,
[onChangeProperty]: this.onChange
}}
/>
}
};
OnChangeDebounce.propTypes={
onDebounce: PropTypes.func.isRequired,
valueProperty: PropTypes.string,
onChangeProperty: PropTypes.string,
getValueFromEvent: PropTypes.func,
wait: PropTypes.number,
waitOptions: PropTypes.shape({
leading: PropTypes.bool,
maxWait: PropTypes.number,
trailing: PropTypes.bool
})
};
OnChangeDebounce.defaultProps={
valueProperty:'value',
onChangeProperty:'onChange',
wait: 300,
waitOptions:null,
getValueFromEvent:(e)=> e&& e.target && e.target.value
};
export default debounceProps => As => props =>
<OnChangeDebounce as={As} {...props} {...debounceProps}/>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment