From e4b0a6325f08ada37de1d70534c4978d17d68f30 Mon Sep 17 00:00:00 2001 From: James Gatz Date: Wed, 3 Jul 2024 16:27:22 +0200 Subject: [PATCH] Fix stale state updates on key-value editor (#7654) --- .../key-value-editor/key-value-editor.tsx | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/insomnia/src/ui/components/key-value-editor/key-value-editor.tsx b/packages/insomnia/src/ui/components/key-value-editor/key-value-editor.tsx index a3f8506a3..6f4dd0c9f 100644 --- a/packages/insomnia/src/ui/components/key-value-editor/key-value-editor.tsx +++ b/packages/insomnia/src/ui/components/key-value-editor/key-value-editor.tsx @@ -59,9 +59,9 @@ const EditableOneLineEditorModal = ({ const handler = createKeybindingsHandler({ 'Enter': e => { e.preventDefault(); - setIsOpen(false); onChange(value); setValue(value); + setIsOpen(false); }, }); @@ -205,30 +205,32 @@ export const KeyValueEditor: FC = ({ getKey: item => item.id, }); - function upsertPair(pair: typeof pairsList.items[0]) { + const upsertPair = useCallback(function upsertPair(pair: typeof pairsList.items[0]) { if (pairsList.getItem(pair.id)) { pairsList.update(pair.id, pair); - onChange(pairsList.items.map(item => (item.id === pair.id ? pair : item))); + const items = pairsList.items.map(item => (item.id === pair.id ? pair : item)); + onChange(items); } else { const id = pair.id === 'pair-empty' ? generateId('pair') : pair.id; pairsList.append({ ...pair, id }); - onChange(pairsList.items.concat(pair)); + const items = pairsList.items.concat(pair); + onChange(items); } + }, [onChange, pairsList]); - } - - function removePair(id: string) { + const removePair = useCallback(function removePair(id: string) { if (pairsList.getItem(id)) { pairsList.remove(id); - onChange(pairsList.items.filter(pair => pair.id !== id)); + const items = pairsList.items.filter(pair => pair.id !== id); + onChange(items); } - } + }, [onChange, pairsList]); - function removeAllPairs() { + const removeAllPairs = useCallback(function removeAllPairs() { pairsList.setSelectedKeys(new Set(pairsList.items.map(item => item.id))); pairsList.removeSelectedItems(); onChange([]); - } + }, [onChange, pairsList]); const { dragAndDropHooks } = useDragAndDrop({ getItems: keys => @@ -395,7 +397,7 @@ export const KeyValueEditor: FC = ({ dependencies={[showDescription, nunjucksEnabled]} className="flex pt-1 flex-col w-full overflow-y-auto flex-1 relative" dragAndDropHooks={dragAndDropHooks} - items={items} + items={items.map(pair => ({ ...pair, upsertPair, removePair }))} > {pair => { const isFile = pair.type === 'file'; @@ -409,7 +411,7 @@ export const KeyValueEditor: FC = ({ defaultValue={pair.value} readOnly={isDisabled} getAutocompleteConstants={() => handleGetAutocompleteValueConstants?.(pair) || []} - onChange={value => upsertPair({ ...pair, value })} + onChange={value => pair.upsertPair({ ...pair, value })} /> ); @@ -421,7 +423,7 @@ export const KeyValueEditor: FC = ({ disabled={isDisabled} className="px-2 py-1 w-full fle flex-shrink-0 flex-1 items-center justify-center gap-2 aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm overflow-hidden" path={pair.fileName || ''} - onChange={fileName => upsertPair({ ...pair, fileName })} + onChange={fileName => pair.upsertPair({ ...pair, fileName })} /> ); } @@ -437,8 +439,8 @@ export const KeyValueEditor: FC = ({ defaultValue: pair.value, enableRender: nunjucksEnabled, mode: pair.multiline && typeof pair.multiline === 'string' ? pair.multiline : 'text/plain', - onChange: (value: string) => upsertPair({ ...pair, value }), - onModeChange: (mode: string) => upsertPair({ ...pair, multiline: mode }), + onChange: (value: string) => pair.upsertPair({ ...pair, value }), + onModeChange: (mode: string) => pair.upsertPair({ ...pair, multiline: mode }), })} > @@ -466,7 +468,7 @@ export const KeyValueEditor: FC = ({ defaultValue={pair.name} readOnly={isDisabled} getAutocompleteConstants={() => handleGetAutocompleteNameConstants?.(pair) || []} - onChange={name => upsertPair({ ...pair, name })} + onChange={name => pair.upsertPair({ ...pair, name })} /> {valueEditor} {showDescription && ( @@ -475,7 +477,7 @@ export const KeyValueEditor: FC = ({ placeholder={descriptionPlaceholder || 'Description'} defaultValue={pair.description || ''} readOnly={isDisabled} - onChange={description => upsertPair({ ...pair, description })} + onChange={description => pair.upsertPair({ ...pair, description })} /> )} @@ -497,14 +499,14 @@ export const KeyValueEditor: FC = ({ id: 'text', name: 'Text', textValue: 'Text', - onAction: () => upsertPair({ ...pair, type: 'text', multiline: false }), + onAction: () => pair.upsertPair({ ...pair, type: 'text', multiline: false }), }, ...allowMultiline ? [ { id: 'multiline-text', name: 'Multiline text', textValue: 'Multiline text', - onAction: () => upsertPair({ ...pair, type: 'text', multiline: true }), + onAction: () => pair.upsertPair({ ...pair, type: 'text', multiline: true }), }, ] : [], ...allowFile ? [ @@ -512,7 +514,7 @@ export const KeyValueEditor: FC = ({ id: 'file', name: 'File', textValue: 'File', - onAction: () => upsertPair({ ...pair, type: 'file' }), + onAction: () => pair.upsertPair({ ...pair, type: 'file' }), }, ] : [], ]} @@ -533,7 +535,7 @@ export const KeyValueEditor: FC = ({ upsertPair({ ...pair, disabled: !isSelected })} + onChange={isSelected => pair.upsertPair({ ...pair, disabled: !isSelected })} isSelected={!pair.disabled} > @@ -543,7 +545,7 @@ export const KeyValueEditor: FC = ({ className="flex items-center disabled:opacity-50 justify-center h-7 aspect-square aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm" confirmMessage='' doneMessage='' - onClick={() => removePair(pair.id)} + onClick={() => pair.removePair(pair.id)} >