diff --git a/src/app/WardrobePage/ItemsPanel.js b/src/app/WardrobePage/ItemsPanel.js index a89a93c..d9fbf00 100644 --- a/src/app/WardrobePage/ItemsPanel.js +++ b/src/app/WardrobePage/ItemsPanel.js @@ -367,11 +367,14 @@ function useOutfitSaving(outfitState, dispatchToOutfit) { // Also, send a `reset` action, to show whatever the server returned. // This is important for suffix changes to `name`, but can also be // relevant for graceful failure when a bug causes a change not to - // persist. - dispatchToOutfit({ - type: "resetToSavedOutfitData", - savedOutfitData: outfit, - }); + // persist. (But don't do it if it's not the current outfit anymore, + // we don't want laggy mutations to reset the outfit!) + if (outfit.id === outfitState.id) { + dispatchToOutfit({ + type: "resetToSavedOutfitData", + savedOutfitData: outfit, + }); + } }, } ); @@ -423,7 +426,12 @@ function useOutfitSaving(outfitState, dispatchToOutfit) { // than the saved state. const debouncedOutfitState = useDebounce( outfitState.outfitStateWithoutExtras, - 2000 + 2000, + { + // When the outfit ID changes, update the debounced state immediately! + forceReset: (debouncedOutfitState, newOutfitState) => + debouncedOutfitState.id !== newOutfitState.id, + } ); // HACK: This prevents us from auto-saving the outfit state that's still // loading. I worry that this might not catch other loading scenarios diff --git a/src/app/util.js b/src/app/util.js index 1810467..cc1c4ce 100644 --- a/src/app/util.js +++ b/src/app/util.js @@ -164,7 +164,7 @@ export function safeImageUrl(urlString) { export function useDebounce( value, delay, - { waitForFirstPause = false, initialValue = null, forceReset = false } = {} + { waitForFirstPause = false, initialValue = null, forceReset = null } = {} ) { // State and setters for debounced value const [debouncedValue, setDebouncedValue] = React.useState( @@ -188,14 +188,17 @@ export function useDebounce( [value, delay] // Only re-call effect if value or delay changes ); - // The `forceReset` option sets the value immediately! + // The `forceReset` option helps us decide whether to set the value + // immediately! We'll update it in an effect for consistency and clarity, but + // also return it immediately rather than wait a tick. + const shouldForceReset = forceReset && forceReset(debouncedValue, value); React.useEffect(() => { - if (forceReset) { + if (shouldForceReset) { setDebouncedValue(value); } - }, [value, forceReset]); + }, [shouldForceReset, value]); - return debouncedValue; + return shouldForceReset ? value : debouncedValue; } /**