source: node_modules/react-debounce-input/src/Component.js@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 4.9 KB
Line 
1import React from 'react';
2import PropTypes from 'prop-types';
3import debounce from 'lodash.debounce';
4
5
6export class DebounceInput extends React.PureComponent {
7 static propTypes = {
8 element: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
9 type: PropTypes.string,
10 onChange: PropTypes.func.isRequired,
11 onKeyDown: PropTypes.func,
12 onBlur: PropTypes.func,
13 value: PropTypes.oneOfType([
14 PropTypes.string,
15 PropTypes.number
16 ]),
17 minLength: PropTypes.number,
18 debounceTimeout: PropTypes.number,
19 forceNotifyByEnter: PropTypes.bool,
20 forceNotifyOnBlur: PropTypes.bool,
21 inputRef: PropTypes.func
22 };
23
24
25 static defaultProps = {
26 element: 'input',
27 type: 'text',
28 onKeyDown: undefined,
29 onBlur: undefined,
30 value: undefined,
31 minLength: 0,
32 debounceTimeout: 100,
33 forceNotifyByEnter: true,
34 forceNotifyOnBlur: true,
35 inputRef: undefined
36 };
37
38
39 constructor(props) {
40 super(props);
41
42 this.isDebouncing = false;
43 this.state = {value: typeof props.value === 'undefined' || props.value === null ? '' : props.value};
44
45 const {debounceTimeout} = this.props;
46 this.createNotifier(debounceTimeout);
47 }
48
49
50 componentDidUpdate(prevProps) {
51 if (this.isDebouncing) {
52 return;
53 }
54 const {value, debounceTimeout} = this.props;
55
56 const {debounceTimeout: oldTimeout, value: oldValue} = prevProps;
57 const {value: stateValue} = this.state;
58
59 if (typeof value !== 'undefined' && oldValue !== value && stateValue !== value) {
60 // Update state.value if new value passed via props, yep re-render should happen
61 // eslint-disable-next-line react/no-did-update-set-state
62 this.setState({value});
63 }
64 if (debounceTimeout !== oldTimeout) {
65 this.createNotifier(debounceTimeout);
66 }
67 }
68
69
70 componentWillUnmount() {
71 if (this.flush) {
72 this.flush();
73 }
74 }
75
76
77 onChange = event => {
78 event.persist();
79
80 const {value: oldValue} = this.state;
81 const {minLength} = this.props;
82
83 this.setState({value: event.target.value}, () => {
84 const {value} = this.state;
85
86 if (value.length >= minLength) {
87 this.notify(event);
88 return;
89 }
90
91 // If user hits backspace and goes below minLength consider it cleaning the value
92 if (oldValue.length > value.length) {
93 this.notify({...event, target: {...event.target, value: ''}});
94 }
95 });
96 };
97
98
99 onKeyDown = event => {
100 if (event.key === 'Enter') {
101 this.forceNotify(event);
102 }
103 // Invoke original onKeyDown if present
104 const {onKeyDown} = this.props;
105 if (onKeyDown) {
106 event.persist();
107 onKeyDown(event);
108 }
109 };
110
111
112 onBlur = event => {
113 this.forceNotify(event);
114 // Invoke original onBlur if present
115 const {onBlur} = this.props;
116 if (onBlur) {
117 event.persist();
118 onBlur(event);
119 }
120 };
121
122
123 createNotifier = debounceTimeout => {
124 if (debounceTimeout < 0) {
125 this.notify = () => null;
126 } else if (debounceTimeout === 0) {
127 this.notify = this.doNotify;
128 } else {
129 const debouncedChangeFunc = debounce(event => {
130 this.isDebouncing = false;
131 this.doNotify(event);
132 }, debounceTimeout);
133
134 this.notify = event => {
135 this.isDebouncing = true;
136 debouncedChangeFunc(event);
137 };
138
139 this.flush = () => debouncedChangeFunc.flush();
140
141 this.cancel = () => {
142 this.isDebouncing = false;
143 debouncedChangeFunc.cancel();
144 };
145 }
146 };
147
148
149 doNotify = (...args) => {
150 const {onChange} = this.props;
151
152 onChange(...args);
153 };
154
155
156 forceNotify = event => {
157 const {debounceTimeout} = this.props;
158 if (!this.isDebouncing && debounceTimeout > 0) {
159 return;
160 }
161
162 if (this.cancel) {
163 this.cancel();
164 }
165
166 const {value} = this.state;
167 const {minLength} = this.props;
168
169 if (value.length >= minLength) {
170 this.doNotify(event);
171 } else {
172 this.doNotify({...event, target: {...event.target, value}});
173 }
174 };
175
176
177 render() {
178 const {
179 element,
180 onChange: _onChange,
181 value: _value,
182 minLength: _minLength,
183 debounceTimeout: _debounceTimeout,
184 forceNotifyByEnter,
185 forceNotifyOnBlur,
186 onKeyDown,
187 onBlur,
188 inputRef,
189 ...props
190 } = this.props;
191 const {value} = this.state;
192
193 let maybeOnKeyDown;
194 if (forceNotifyByEnter) {
195 maybeOnKeyDown = {onKeyDown: this.onKeyDown};
196 } else if (onKeyDown) {
197 maybeOnKeyDown = {onKeyDown};
198 } else {
199 maybeOnKeyDown = {};
200 }
201
202 let maybeOnBlur;
203 if (forceNotifyOnBlur) {
204 maybeOnBlur = {onBlur: this.onBlur};
205 } else if (onBlur) {
206 maybeOnBlur = {onBlur};
207 } else {
208 maybeOnBlur = {};
209 }
210
211 const maybeRef = inputRef ? {ref: inputRef} : {};
212
213 return React.createElement(element, {
214 ...props,
215 onChange: this.onChange,
216 value,
217 ...maybeOnKeyDown,
218 ...maybeOnBlur,
219 ...maybeRef
220 });
221 }
222}
Note: See TracBrowser for help on using the repository browser.