diff --git a/.eslintrc.js b/.eslintrc.js index 6acd1ddcd..0282b4e56 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,6 +25,7 @@ module.exports = { 'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], 'import/extensions': 0, '@typescript-eslint/camelcase': ['error', { allow: ['__autocomplete_id'] }], + '@typescript-eslint/no-use-before-define': 0, // Useful to call functions like `nodeItem?.scrollIntoView()`. 'no-unused-expressions': 0, complexity: 0, diff --git a/packages/autocomplete-js/src/autocomplete.ts b/packages/autocomplete-js/src/autocomplete.ts index 6b1c01b6f..a212c8eab 100644 --- a/packages/autocomplete-js/src/autocomplete.ts +++ b/packages/autocomplete-js/src/autocomplete.ts @@ -48,7 +48,14 @@ export function autocomplete({ classNames, }); - function onStateChange(state: AutocompleteState) { + // This batches state changes to limit DOM mutations. + // Every time we call a setter in `autocomplete-core` (e.g., in `onInput`), + // the core `onStateChange` function is called. + // We don't need to be notified of all these state changes to render. + // As an example: + // - without debouncing: "iphone case" query → 85 renders + // - with debouncing: "iphone case" query → 12 renders + const onStateChange = debounce((state: AutocompleteState) => { render(renderer, { state, ...autocomplete, @@ -61,7 +68,7 @@ export function autocomplete({ panel, resetButton, }); - } + }, 0); function setPanelPosition() { setProperties(panel, {