mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-10-03 09:05:17 -07:00
perf(settings): persist generation sliders on release, not per pointer-move
Both sliders on the generation settings page were calling update() — which is a React Query mutation that PATCHes /settings/generation — inside onValueChange. Dragging the chunk-limit slider from 800 to 3000 fired a request per pointer-move pixel, and a mid-drag failure plus optimistic rollback would leave persisted state visibly out of sync with the thumb position. Local state now mirrors each slider during a drag and the persist happens once on Radix's onValueCommit (pointer-up / keyboard-release). useEffects keep the local state in sync if the persisted value changes out-of-band — another window editing the same setting still updates the slider position cleanly.
This commit is contained in:
@@ -14,10 +14,17 @@ export function GenerationPage() {
|
|||||||
const platform = usePlatform();
|
const platform = usePlatform();
|
||||||
const serverUrl = useServerStore((state) => state.serverUrl);
|
const serverUrl = useServerStore((state) => state.serverUrl);
|
||||||
const { settings, update } = useGenerationSettings();
|
const { settings, update } = useGenerationSettings();
|
||||||
const maxChunkChars = settings?.max_chunk_chars ?? 800;
|
const persistedMaxChunkChars = settings?.max_chunk_chars ?? 800;
|
||||||
const crossfadeMs = settings?.crossfade_ms ?? 50;
|
const persistedCrossfadeMs = settings?.crossfade_ms ?? 50;
|
||||||
const normalizeAudio = settings?.normalize_audio ?? true;
|
const normalizeAudio = settings?.normalize_audio ?? true;
|
||||||
const autoplayOnGenerate = settings?.autoplay_on_generate ?? true;
|
const autoplayOnGenerate = settings?.autoplay_on_generate ?? true;
|
||||||
|
// Slider mirrors persist on commit (pointer-up / keyboard-release) only —
|
||||||
|
// onValueChange would fire a PATCH for every pointer-move pixel and round-
|
||||||
|
// trip mid-drag failures could leave persisted state out of sync with UI.
|
||||||
|
const [maxChunkChars, setMaxChunkChars] = useState(persistedMaxChunkChars);
|
||||||
|
const [crossfadeMs, setCrossfadeMs] = useState(persistedCrossfadeMs);
|
||||||
|
useEffect(() => setMaxChunkChars(persistedMaxChunkChars), [persistedMaxChunkChars]);
|
||||||
|
useEffect(() => setCrossfadeMs(persistedCrossfadeMs), [persistedCrossfadeMs]);
|
||||||
const [opening, setOpening] = useState(false);
|
const [opening, setOpening] = useState(false);
|
||||||
const [generationsPath, setGenerationsPath] = useState<string | null>(null);
|
const [generationsPath, setGenerationsPath] = useState<string | null>(null);
|
||||||
|
|
||||||
@@ -64,7 +71,8 @@ export function GenerationPage() {
|
|||||||
<Slider
|
<Slider
|
||||||
id="maxChunkChars"
|
id="maxChunkChars"
|
||||||
value={[maxChunkChars]}
|
value={[maxChunkChars]}
|
||||||
onValueChange={([value]) => update({ max_chunk_chars: value })}
|
onValueChange={([value]) => setMaxChunkChars(value)}
|
||||||
|
onValueCommit={([value]) => update({ max_chunk_chars: value })}
|
||||||
min={100}
|
min={100}
|
||||||
max={5000}
|
max={5000}
|
||||||
step={50}
|
step={50}
|
||||||
@@ -86,7 +94,8 @@ export function GenerationPage() {
|
|||||||
<Slider
|
<Slider
|
||||||
id="crossfadeMs"
|
id="crossfadeMs"
|
||||||
value={[crossfadeMs]}
|
value={[crossfadeMs]}
|
||||||
onValueChange={([value]) => update({ crossfade_ms: value })}
|
onValueChange={([value]) => setCrossfadeMs(value)}
|
||||||
|
onValueCommit={([value]) => update({ crossfade_ms: value })}
|
||||||
min={0}
|
min={0}
|
||||||
max={200}
|
max={200}
|
||||||
step={10}
|
step={10}
|
||||||
|
|||||||
Reference in New Issue
Block a user