Fix flash of content when emptying search field

1. Search for something
2. Clear the search bar
3. Quickly start typing something new

Before this change, the results would clear on #2, but then the old results would show up again during #3, before the loading state for the new query.

This matches the logic, right? We hid the results when both the current and debounced query were empty, and, during that time, neither is empty.

Instead, here we update the `useDebounce` hook to have a `forceReset` option, to immediately clear out the value instead of waiting.
This commit is contained in:
Emi Matchu 2021-01-21 16:03:14 -08:00
parent 701eb33391
commit 11fae604be
2 changed files with 14 additions and 10 deletions

View file

@ -91,14 +91,11 @@ function ItemSearchPageResults({ query: latestQuery }) {
const query = useDebounce(latestQuery, 300, {
waitForFirstPause: true,
initialValue: emptySearchQuery,
});
// We'll skip all this if the query is empty. We also check the latest query
// for this, without waiting for the debounce, in order to get fast feedback
// when clearing the query. But we _do_ still check the debounced query too,
// which gives us _slow_ feedback when moving from empty to _non_-empty.
const skipSearchResults =
searchQueryIsEmpty(query) || searchQueryIsEmpty(latestQuery);
// When the query is empty, clear the debounced query immediately too! That
// will give us fast feedback when the search field clears.
forceReset: searchQueryIsEmpty(latestQuery),
});
// NOTE: This query should always load ~instantly, from the client cache.
const { data: zoneData } = useQuery(gql`
@ -147,11 +144,11 @@ function ItemSearchPageResults({ query: latestQuery }) {
zoneIds: filterToZoneIds,
},
context: { sendAuth: true },
skip: skipSearchResults,
skip: searchQueryIsEmpty(query),
}
);
if (skipSearchResults) {
if (searchQueryIsEmpty(query)) {
return null;
}

View file

@ -141,7 +141,7 @@ export function safeImageUrl(urlString) {
export function useDebounce(
value,
delay,
{ waitForFirstPause = false, initialValue = null } = {}
{ waitForFirstPause = false, initialValue = null, forceReset = false } = {}
) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = React.useState(
@ -165,6 +165,13 @@ export function useDebounce(
[value, delay] // Only re-call effect if value or delay changes
);
// The `forceReset` option sets the value immediately!
React.useEffect(() => {
if (forceReset) {
setDebouncedValue(value);
}
}, [value, forceReset]);
return debouncedValue;
}