fix(tasks): switching lists never shows the previous list's tasks

The new list's view (list or Kanban) appeared one render before its
tasks, so the board briefly showed the old list. Lists opened in this
session are kept in memory and shown in the same render; a list not
opened yet takes its share of "Alle Aufgaben", else the loading
placeholder shows. The reload brings them up to date.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-11-02 18:11:17 +01:00
1 parent cce076b093
commit 92de62a620
1 file changed
+36 -2
+36 -2
View File
@@ -173,7 +173,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
const [filter, setFilter] = useState<'open' | 'done' | 'discarded'>('open');
const [tasks, setTasks] = useState<Thought[]>([]);
const [taskLists, setTaskLists] = useState<TaskList[]>([]);
const [selectedListId, setSelectedListId] = useState<string>(
const [selectedListId, setSelectedListIdState] = useState<string>(
() => remembered.listId || 'all'
);
const viewMode: ViewMode = viewModes[selectedListId] || 'list';
@@ -304,6 +304,10 @@ export const TasksView: React.FC<TasksViewProps> = ({
]);
if (seq !== loadSeqRef.current) return; // a newer reload is under way
loadedListRef.current = listId;
listCacheRef.current.set(listId, {
tasks: Array.isArray(allTasks) ? allTasks : [],
trash: Array.isArray(trash) ? trash : [],
});
setTasks(Array.isArray(allTasks) ? allTasks : []);
setTaskLists(Array.isArray(allLists) ? allLists : []);
// The remembered list was deleted or unshared meanwhile
@@ -327,6 +331,33 @@ export const TasksView: React.FC<TasksViewProps> = ({
const selectedListIdRef = useRef(selectedListId);
selectedListIdRef.current = selectedListId;
// Last known tasks of every list opened in this session. Switching lists shows them in the same render
// as the new list's view (list or Kanban), so the board never flashes the previous list's tasks; the
// reload then brings them up to date. A list not opened yet takes its share of "Alle Aufgaben".
const listCacheRef = useRef(new Map<string, { tasks: Thought[]; trash: TrashedTask[] }>());
useEffect(() => {
if (!loading && loadedListRef.current === selectedListId) {
listCacheRef.current.set(selectedListId, { tasks, trash: taskTrash });
}
}, [tasks, taskTrash, loading, selectedListId]);
const setSelectedListId = useCallback((id: string) => {
if (id === selectedListIdRef.current) return;
const cache = listCacheRef.current;
let known = cache.get(id);
const all = cache.get('all');
if (!known && id !== 'all' && all) {
known = {
tasks: all.tasks.filter((t) => t.taskListId === id),
trash: all.trash.filter((t) => t.taskListId === id),
};
}
setTasks(known ? known.tasks : []);
setTaskTrash(known ? known.trash : []);
setLoading(!known);
loadedListRef.current = known ? id : null;
setSelectedListIdState(id);
}, []);
const onRefreshStatsRef = useRef(onRefreshStats);
onRefreshStatsRef.current = onRefreshStats;
// The realtime handler is registered once; it must reload with the current list, not the first one
@@ -1371,7 +1402,9 @@ export const TasksView: React.FC<TasksViewProps> = ({
try {
await api.deleteTaskList(listId);
setTaskLists((prev) => prev.filter((l) => l.id !== listId));
setSelectedListId('all');
// Plain switch: the deleted list's tasks belong to "Alle Aufgaben" anyway (and the menu effect keeps
// this handler out of its dependencies)
setSelectedListIdState('all');
} catch (err: any) {
alert(err.message);
}
@@ -1568,6 +1601,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
groupBy,
defaultGroupBy,
setViewMode,
setSelectedListId,
sortBy,
openTasks.length,
doneTasks.length,