You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter待办列表添加任务重复显示问题求助

任务重复显示问题的排查与修复

这种问题我之前也遇到过,大多是状态更新时没生成新列表实例或者数据层重复追加数据导致的,结合你的场景,分几个点来修复:

1. 修正Cubit的状态更新逻辑

如果你的Cubit直接修改现有状态里的列表再emit,Flutter的Widget会因为列表引用未变,误以为数据没更新,进而导致重复渲染。必须创建新的列表副本:

错误写法:

void addTodo(String task) {
  final newTodo = Todo(task: task);
  state.todos.add(newTodo); // 直接修改原列表,引用未改变
  emit(TodoLoaded(todos: state.todos));
}

修复后:

void addTodo(String task) {
  final newTodo = Todo(task: task);
  // 用List.from创建新列表实例,再添加新任务
  final updatedTodos = List<Todo>.from(state.todos)..add(newTodo);
  emit(TodoLoaded(todos: updatedTodos));
}

2. 检查ToDoRepository的存储逻辑

如果Repository每次添加任务时都重复读取旧数据并追加,必然会导致任务重复。比如:

错误写法(Repository):

class TodoRepository {
  List<Todo> _todos = [];

  Future<void> addTodo(Todo todo) async {
    final savedTodos = await _loadFromStorage();
    savedTodos.add(todo);
    _todos = savedTodos;
    await _saveToStorage(_todos);
  }

  Future<List<Todo>> getTodos() async {
    final savedTodos = await _loadFromStorage();
    _todos.addAll(savedTodos); // 每次获取都往本地缓存追加,数据越积越多
    return _todos;
  }
}

修复后:

class TodoRepository {
  Future<void> addTodo(Todo todo) async {
    final savedTodos = await _loadFromStorage();
    // 可选:先判断任务是否已存在,避免添加完全重复的任务
    if (!savedTodos.any((t) => t.task == todo.task)) {
      savedTodos.add(todo);
      await _saveToStorage(savedTodos);
    }
  }

  Future<List<Todo>> getTodos() async {
    // 直接返回存储的列表,不与本地缓存重复合并
    return await _loadFromStorage();
  }
}

3. 页面组件避免多余的状态操作

比如在TextField的onSubmitted中重复触发状态加载,或者在build方法中重复创建列表:

错误写法(页面组件):

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: TextField(
        onSubmitted: (value) {
          context.read<TodoCubit>().addTodo(value);
          context.read<TodoCubit>().getTodos(); // 多此一举,addTodo后应自动更新状态
        },
      ),
    ),
    body: BlocBuilder<TodoCubit, TodoState>(
      builder: (context, state) {
        final todos = [...state.todos]; // 每次build都生成新列表,可能触发重复渲染
        return ListView.builder(
          itemCount: todos.length,
          itemBuilder: (_, index) => ListTile(title: Text(todos[index].task)),
        );
      },
    ),
  );
}

修复后:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: TextField(
        onSubmitted: (value) {
          context.read<TodoCubit>().addTodo(value);
          // 无需额外调用getTodos,Cubit内部应处理状态更新
        },
      ),
    ),
    body: BlocBuilder<TodoCubit, TodoState>(
      builder: (context, state) {
        if (state is TodoLoaded) {
          return ListView.builder(
            itemCount: state.todos.length,
            itemBuilder: (_, index) => ListTile(title: Text(state.todos[index].task)),
          );
        }
        return const Center(child: CircularProgressIndicator());
      },
    ),
  );
}

4. 初始化时避免重复加载数据

如果Cubit构造函数中多次调用getTodos(),或者页面初始化时重复触发加载,也会导致任务重复。确保只加载一次:

class TodoCubit extends Cubit<TodoState> {
  final TodoRepository repository;

  TodoCubit(this.repository) : super(TodoInitial()) {
    _loadTodos(); // 仅在初始化时加载一次数据
  }

  Future<void> _loadTodos() async {
    final todos = await repository.getTodos();
    emit(TodoLoaded(todos: todos));
  }

  void addTodo(String task) async {
    final newTodo = Todo(task: task);
    await repository.addTodo(newTodo);
    // 重新加载最新列表,或直接使用本地更新后的列表(二选一即可)
    final updatedTodos = await repository.getTodos();
    emit(TodoLoaded(todos: updatedTodos));
  }
}

核心修复思路就是:保证每次状态更新都使用新的列表实例,同时避免数据层重复追加数据,这样就能解决任务重复显示的问题。


内容的提问来源于stack exchange,提问作者NataliaS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:45:36