diff --git a/internal/DebounceDecorator/DebounceDecorator.js b/internal/DebounceDecorator/DebounceDecorator.js index ddef0feac2..0fc82c3c24 100644 --- a/internal/DebounceDecorator/DebounceDecorator.js +++ b/internal/DebounceDecorator/DebounceDecorator.js @@ -8,7 +8,7 @@ import hoc from '@enact/core/hoc'; import {Job} from '@enact/core/util'; import PropTypes from 'prop-types'; -import {Component} from 'react'; +import {useCallback, useEffect, useRef} from 'react'; /** * Default config for {@link sandstone/internal/DebounceDecorator.DebounceDecorator}. @@ -60,66 +60,75 @@ const defaultConfig = { const DebounceDecorator = hoc(defaultConfig, (config, Wrapped) => { const {cancel, debounce, delay} = config; - return class extends Component { - static displayName = 'DebounceDecorator'; - - static propTypes = /** @lends sandstone/internal/DebounceDecorator.DebounceDecorator.prototype */ { - /** - * Handler for `onChange` events - * - * `'onChange'` can be changed to a different prop name by specifying the `debounce` - * config option. - * - * @see {@link sandstone/internal/DebounceDecorator.DebounceDecorator.defaultConfig#debounce} - * @name onChange - * @memberof sandstone/internal/DebounceDecorator.DebounceDecorator.prototype - * @type {Function} - * @public - */ - [debounce]: PropTypes.func - }; - - constructor (props) { - super(props); - this.job = new Job(this.emitEvent.bind(this), delay); - } - - componentWillUnmount () { - this.job.stop(); - } + // eslint-disable-next-line no-shadow + const DebounceDecorator = (props) => { + let debounceProps = props; - emitEvent (ev) { - if (this.props[debounce]) { - this.props[debounce](ev); + const emitEvent = useCallback((ev) => { + if (props[debounce]) { + props[debounce](ev); } - } + }, [props]); - handleEvent = (ev) => { - this.job.start(ev); - }; + const emitEventRef = useRef(emitEvent); + const job = useRef(new Job(emitEventRef.current, delay)); - handleCancel = (ev) => { - if (this.props[cancel]) { - this.props[cancel](ev); + useEffect(() => { + if (emitEvent !== emitEventRef.current) { + emitEventRef.current = emitEvent; + job.current.stop(); + job.current = new Job(emitEvent, delay); } - this.job.stop(); - }; + }, [emitEvent]); - render () { - let props = this.props; + useEffect(() => { + return () => { + job.current.stop(); + }; + }, []); - if (debounce || cancel) { - props = {...props}; + const handleEvent = useCallback((ev) => { + job.current.start(ev); + }, []); - if (debounce) props[debounce] = this.handleEvent; - if (cancel) props[cancel] = this.handleCancel; + const handleCancel = useCallback((ev) => { + if (props[cancel]) { + props[cancel](ev); } + job.current.stop(); + }, [props]); + + if (debounce || cancel) { + debounceProps = {...props}; - return ( - - ); + if (debounce) debounceProps[debounce] = handleEvent; + if (cancel) debounceProps[cancel] = handleCancel; } + + return ( + + ); + }; + + DebounceDecorator.displayName = 'DebounceDecorator'; + + DebounceDecorator.propTypes = {/** @lends sandstone/internal/DebounceDecorator.DebounceDecorator.prototype */ + /** + * Handler for `onChange` events + * + * `'onChange'` can be changed to a different prop name by specifying the `debounce` + * config option. + * + * @see {@link sandstone/internal/DebounceDecorator.DebounceDecorator.defaultConfig#debounce} + * @name onChange + * @memberof sandstone/internal/DebounceDecorator.DebounceDecorator.prototype + * @type {Function} + * @public + */ + [debounce]: PropTypes.func }; + + return DebounceDecorator; }); export default DebounceDecorator;