fix: KVEditor effect dependency uses stable JSON serialization

Replace the flawed join-based comparison (entryKeys.join(',')) with
JSON.stringify() to properly handle keys containing commas. The previous
implementation could produce false equality when different key sets
shared the same comma-separated representation (e.g., 'a,b' key vs
separate 'a' and 'b' keys).

This ensures the effect fires correctly when keys change, fixing silent
failures to update derived state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-23 09:41:49 +02:00
parent 9375430e02
commit 6d5be523ab
3 changed files with 25 additions and 22 deletions

View File

@@ -12,7 +12,7 @@ export function KVEditor({ entries, onChange }: KVEditorProps): React.JSX.Elemen
const styles = useConfigStyles();
const rows = useMemo(() => Object.entries(entries), [entries]);
const entryKeys = useMemo(() => Object.keys(entries), [entries]);
const entryKeyList = entryKeys.join(",");
const entryKeysJson = useMemo(() => JSON.stringify(entryKeys), [entryKeys]);
const [editedKeys, setEditedKeys] = useState<Record<string, string>>(
Object.fromEntries(rows.map(([key]) => [key, key])),
);
@@ -27,7 +27,7 @@ export function KVEditor({ entries, onChange }: KVEditorProps): React.JSX.Elemen
.map((key) => [key, previousErrors[key] ?? ""]),
),
);
}, [entryKeyList, rows, entryKeys]);
}, [entryKeysJson, rows, entryKeys]);
const validateKey = (oldKey: string, newKey: string): string | null => {
const trimmedKey = newKey.trim();

View File

@@ -34,4 +34,27 @@ describe("KVEditor", () => {
expect(handleChange).toHaveBeenCalledWith({ primary: "1", second: "2" });
});
it("correctly distinguishes keys with commas from separate keys", () => {
const handleChange = vi.fn();
const { rerender } = render(
<FluentProvider theme={webLightTheme}>
<KVEditor entries={{ "a,b": "1", c: "2" }} onChange={handleChange} />
</FluentProvider>,
);
expect(screen.getByLabelText(/Setting name: a,b/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Setting name: c/i)).toBeInTheDocument();
// Verify that changing to separate keys is recognized as a different state
rerender(
<FluentProvider theme={webLightTheme}>
<KVEditor entries={{ a: "1", b: "1", c: "2" }} onChange={handleChange} />
</FluentProvider>,
);
expect(screen.getByLabelText(/Setting name: a/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Setting name: b/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Setting name: c/i)).toBeInTheDocument();
});
});