fix(playlists): a list reopened from the cache keeps its rows
Leaving the Playlists page and coming back painted the selected list empty ("0 videos") while
the rail counted its rows. The page re-seeds its undoable order from the cached list in an
effect; StrictMode runs that effect twice on the remount, so a reset was followed in the same
tick by a rebase. Since E32 S3 a reset is state only and the rebase read the mirror ref, which
still held the empty initial history, and wrote it back over the reset.
rebase is now a state updater, so it builds on whatever an earlier call in the tick installed.
Both tests seen RED (hook: [] for [10, 20]; page: no rows), and the bug reproduced in the
browser on the old hook.
This commit is contained in:
@@ -81,7 +81,8 @@ export function useUndoable<T>(
|
||||
onApplyRef.current?.(next);
|
||||
}, [commit, onApplyRef]);
|
||||
|
||||
// State only: safe to call during render. The other actions see it from the next commit on.
|
||||
// State only: safe to call during render. `rebase` builds on it at once; `set`/`undo`/`redo` read
|
||||
// the mirror, so they see it from the next commit on (no caller acts in the tick of a reset).
|
||||
const reset = useCallback((value: T) => {
|
||||
setH({ past: [], present: value, future: [] });
|
||||
}, []);
|
||||
@@ -91,17 +92,12 @@ export function useUndoable<T>(
|
||||
// removing a playlist item is not itself undoable, yet dropping it from each stored order keeps
|
||||
// the user's reorder history valid and usable instead of throwing it away (which is what a
|
||||
// `reset` does). No `onApply`: the caller is already persisting the change by its own route.
|
||||
const rebase = useCallback(
|
||||
(map: (value: T) => T) => {
|
||||
const s = ref.current;
|
||||
commit({
|
||||
past: s.past.map(map),
|
||||
present: map(s.present),
|
||||
future: s.future.map(map),
|
||||
});
|
||||
},
|
||||
[commit],
|
||||
);
|
||||
// An updater, not the mirror: a `reset` earlier in the same tick is state only, so the mirror
|
||||
// still held the history before it, and rebasing that wrote the old value back over the reset (a
|
||||
// cached playlist remounted under StrictMode re-seeds with reset-then-rebase and painted empty).
|
||||
const rebase = useCallback((map: (value: T) => T) => {
|
||||
setH((s) => ({ past: s.past.map(map), present: map(s.present), future: s.future.map(map) }));
|
||||
}, []);
|
||||
|
||||
return {
|
||||
value: h.present,
|
||||
|
||||
Reference in New Issue
Block a user