From a66dc2693abd86d6d82954deb5355c77050e301d Mon Sep 17 00:00:00 2001 From: Vaidehi Joshi Date: Mon, 9 Mar 2020 14:38:39 -0700 Subject: [PATCH] Refactor debounce usage into debounceAction util (#6506) * Refactor debounce usage into debounceAction util * Allow debounceAction's config to be merged, allow for named arguments Also clean up the documentation as necessary! --- app/javascript/chat/chat.jsx | 5 ++--- app/javascript/listings/listings.jsx | 19 +++++++++--------- app/javascript/readingList/readingList.jsx | 4 ++-- app/javascript/shared/components/tags.jsx | 6 ++++-- app/javascript/src/utils/debounceAction.js | 23 ++++++++++++++++++++++ 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 app/javascript/src/utils/debounceAction.js diff --git a/app/javascript/chat/chat.jsx b/app/javascript/chat/chat.jsx index cced673ba..5e7ab1a26 100644 --- a/app/javascript/chat/chat.jsx +++ b/app/javascript/chat/chat.jsx @@ -1,6 +1,5 @@ import { h, Component } from 'preact'; import PropTypes from 'prop-types'; -import debounce from 'lodash.debounce'; import ConfigImage from '../../assets/images/three-dots.svg'; import { conductModeration, @@ -25,6 +24,7 @@ import Video from './video'; import View from './view'; import setupPusher from '../src/utils/pusher'; +import debounceAction from '../src/utils/debounceAction'; export default class Chat extends Component { static propTypes = { @@ -39,9 +39,8 @@ export default class Chat extends Component { const chatChannels = JSON.parse(props.chatChannels); const chatOptions = JSON.parse(props.chatOptions); - this.debouncedChannelFilter = debounce( + this.debouncedChannelFilter = debounceAction( this.triggerChannelFilter.bind(this), - 300, ); this.state = { diff --git a/app/javascript/listings/listings.jsx b/app/javascript/listings/listings.jsx index eb24b0c5f..4a10bdea8 100644 --- a/app/javascript/listings/listings.jsx +++ b/app/javascript/listings/listings.jsx @@ -1,5 +1,5 @@ import { h, Component } from 'preact'; -import debounce from 'lodash.debounce'; +import debounceAction from '../src/utils/debounceAction'; import { fetchSearch } from '../src/utils/search'; import SingleListing from './singleListing'; @@ -84,28 +84,29 @@ export class Listings extends Component { const category = container.dataset.category || ''; const allCategories = JSON.parse(container.dataset.allcategories || []); let tags = []; + let openedListing = null; + let slug = null; + let listings = []; + if (params.t) { tags = params.t.split(','); } + const query = params.q || ''; - let listings = []; + if (tags.length === 0 && query === '') { listings = JSON.parse(container.dataset.listings); } - let openedListing = null; - let slug = null; + if (container.dataset.displayedlisting) { openedListing = JSON.parse(container.dataset.displayedlisting); ({ slug } = openedListing); document.body.classList.add('modal-open'); } - t.debouncedClassifiedListingSearch = debounce( + t.debouncedClassifiedListingSearch = debounceAction( this.handleQuery.bind(this), - 150, - { - leading: true, - }, + { time: 150, config: { leading: true } }, ); t.setState({ diff --git a/app/javascript/readingList/readingList.jsx b/app/javascript/readingList/readingList.jsx index 32faf31e1..5d5fb2914 100644 --- a/app/javascript/readingList/readingList.jsx +++ b/app/javascript/readingList/readingList.jsx @@ -1,6 +1,6 @@ import { h, Component } from 'preact'; import { PropTypes } from 'preact-compat'; -import debounce from 'lodash.debounce'; +import debounceAction from '../src/utils/debounceAction'; import { defaultState, @@ -39,7 +39,7 @@ export class ReadingList extends Component { this.state = defaultState({ availableTags, archiving: false, statusView }); // bind and initialize all shared functions - this.onSearchBoxType = debounce(onSearchBoxType.bind(this), 300, { + this.onSearchBoxType = debounceAction(onSearchBoxType.bind(this), { leading: true, }); this.loadNextPage = loadNextPage.bind(this); diff --git a/app/javascript/shared/components/tags.jsx b/app/javascript/shared/components/tags.jsx index afeaf439a..b124b2b94 100644 --- a/app/javascript/shared/components/tags.jsx +++ b/app/javascript/shared/components/tags.jsx @@ -1,6 +1,6 @@ import { h, Component } from 'preact'; import PropTypes from 'prop-types'; -import debounce from 'lodash.debounce'; +import debounceAction from '../../src/utils/debounceAction'; import { fetchSearch } from '../../src/utils/search'; const KEYS = { @@ -34,7 +34,9 @@ class Tags extends Component { // 250ms without invoking the function at the leading edge of the timeout // NOTE: this seems the best combination of wait time and options to avoid // flickering and text replacement during autocomplete - this.debouncedTagSearch = debounce(this.handleInput.bind(this), 250); + this.debouncedTagSearch = debounceAction(this.handleInput.bind(this), { + time: 250, + }); this.state = { selectedIndex: -1, diff --git a/app/javascript/src/utils/debounceAction.js b/app/javascript/src/utils/debounceAction.js new file mode 100644 index 000000000..c8cacd1db --- /dev/null +++ b/app/javascript/src/utils/debounceAction.js @@ -0,0 +1,23 @@ +import debounce from 'lodash.debounce'; + +/** + * A util function to wrap any action with lodash's `debounce` (https://lodash.com/docs/#debounce). + * To use this util, wrap it in the util like so: debounceAction(onSearchBoxType.bind(this)); + * + * By default, this util uses a default time of 300ms, and includes a default config of `{ leading: false }`. + * These values can be overridden: debounceAction(this.onSearchBoxType.bind(this), { time: 100, config: { leading: true }}); + * + * + * @param {Function} action - The function that should be wrapped with `debounce`. + * @param {Number} [time=300] - The number of milliseconds to wait. + * @param {Object} [config={ leading: false }] - Any configuration for the debounce function. + * + * @returns {Function} A function wrapped in `debounce`. + */ +export default function debounceAction( + action, + { time = 300, config = { leading: false } } = {}, +) { + const configs = { ...config }; + return debounce(action, time, configs); +}