From d06873e1fff737f853ac813df21d2b7b365c5446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chalifour?= Date: Mon, 16 Nov 2020 12:10:59 +0100 Subject: [PATCH] feat(js): batch DOM updates (#372) --- .eslintrc.js | 1 + packages/autocomplete-js/src/autocomplete.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 77052e044..e180bc7f8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -26,6 +26,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 f3b0913a3..c198fba9e 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, {