From 72989ea646255b2f2af58da2127a23a8c724c584 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2024 18:52:10 +0000 Subject: [PATCH] Fix force tab complete not working since switching to React 18 createRoot API (#28505) `setState` now has different timings so we cannot assume the state changes are available immediately and must await them Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/Autocomplete.tsx | 45 ++++++++++++--------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index af33fb2d9e..423b5c6272 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -10,6 +10,7 @@ import React, { createRef, KeyboardEvent, RefObject } from "react"; import classNames from "classnames"; import { flatMap } from "lodash"; import { Room } from "matrix-js-sdk/src/matrix"; +import { defer } from "matrix-js-sdk/src/utils"; import Autocompleter, { ICompletion, ISelectionRange, IProviderCompletions } from "../../../autocomplete/Autocompleter"; import SettingsStore from "../../../settings/SettingsStore"; @@ -127,18 +128,21 @@ export default class Autocomplete extends React.PureComponent { } private async processQuery(query: string, selection: ISelectionRange): Promise { - return this.autocompleter - ?.getCompletions(query, selection, this.state.forceComplete, MAX_PROVIDER_MATCHES) - .then((completions) => { - // Only ever process the completions for the most recent query being processed - if (query !== this.queryRequested) { - return; - } - this.processCompletions(completions); - }); + if (!this.autocompleter) return; + const completions = await this.autocompleter.getCompletions( + query, + selection, + this.state.forceComplete, + MAX_PROVIDER_MATCHES, + ); + // Only ever process the completions for the most recent query being processed + if (query !== this.queryRequested) { + return; + } + await this.processCompletions(completions); } - private processCompletions(completions: IProviderCompletions[]): void { + private async processCompletions(completions: IProviderCompletions[]): Promise { const completionList = flatMap(completions, (provider) => provider.completions); // Reset selection when completion list becomes empty. @@ -169,14 +173,19 @@ export default class Autocomplete extends React.PureComponent { } } - this.setState({ - completions, - completionList, - selectionOffset, - hide, - // Force complete is turned off each time since we can't edit the query in that case - forceComplete: false, - }); + const deferred = defer(); + this.setState( + { + completions, + completionList, + selectionOffset, + hide, + // Force complete is turned off each time since we can't edit the query in that case + forceComplete: false, + }, + deferred.resolve, + ); + await deferred.promise; } public hasSelection(): boolean {