Skip to content

Commit

Permalink
Fixed "no results" state flashing in some situations (#1266)
Browse files Browse the repository at this point in the history
ref https://linear.app/tryghost/issue/MOM-160

In Ghost's Ember host app, promises ("tasks") can be cancelled which will occur when the searchLinks function is called in quick succession. That was resulting in a flash of "no results" because promises in React/plain JS don't get cancelled so earlier search promises could end up overwriting the results array whilst a later search was still completing.

- added handling for receiving `undefined` from the `searchLinks` function which indicates a cancelled search
- fixed constant re-creation of search options object prop which caused problems in the hook when it's properties were used in dependency arrays
  • Loading branch information
kevinansfield authored May 30, 2024
1 parent 32ee16a commit e490ae9
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 9 deletions.
11 changes: 10 additions & 1 deletion packages/koenig-lexical/src/hooks/useSearchLinks.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,19 @@ export const useSearchLinks = (query, searchLinks, {noResultOptions} = {}) => {

setIsSearching(true);
const results = await searchLinks(term);

// can return undefined if the search was cancelled, avoid updating
// in that scenario because we can end up in a race condition where
// we overwrite the results with an empty array whilst still waiting
// for a later search to complete. Avoids flashing of "no results".
if (results === undefined) {
return;
}

setListOptions(convertSearchResultsToListOptions(results, {noResultOptions}));
setIsSearching(false);
};
}, [searchLinks]);
}, [searchLinks, noResultOptions]);

const debouncedSearch = React.useMemo(() => {
return debounce(search, DEBOUNCE_MS);
Expand Down
16 changes: 8 additions & 8 deletions packages/koenig-lexical/src/plugins/AtLinkPlugin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,19 @@ function $removeAtLink(node, {focus = false} = {}) {
}
}

function noResultOptions() {
return [{
label: 'No results found'
}];
}

// Manages at-link search nodes and display of the search results panel when appropriate
export const KoenigAtLinkPlugin = ({searchLinks}) => {
const [editor] = useLexicalComposerContext();

const [focusedAtLinkNode, setFocusedAtLinkNode] = React.useState(null);
const [query, setQuery] = React.useState('');
const {isSearching, listOptions} = useSearchLinks(query, searchLinks, {
noResultOptions() {
return [{
label: 'No results found'
}];
}
});
const searchOptions = React.useMemo(() => ({noResultOptions}), []);
const {isSearching, listOptions} = useSearchLinks(query, searchLinks, searchOptions);

// register an event listener to detect '@' character being typed
// - we only ever want to convert an '@' to an at-link node when it's typed
Expand Down

0 comments on commit e490ae9

Please sign in to comment.