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

Flutter Provider访问新分类时先加载旧分类列表数据异常

问题表现
  • 分类跳转商品列表功能存在渲染异常:从分类详情页返回列表后,点击其他分类进入详情页时,页面会先闪显上一个分类的旧商品数据,等待接口返回后才会刷新为当前分类的正确数据。
  • 已在页面dispose生命周期中调用_product.clear(),问题未解决。
原有问题代码
class _CategoryDetailsScreenState extends State<CategoryDetailsScreen> {
     late List  _product;

    @override
    void initState() {
        //ModalRoute not work in init state without future delayed
     Future.delayed(Duration.zero).then((_) 
     {
        var _args = ModalRoute.of(context)!.settings.arguments as CategoryDetailsScreenArgs;
        Provider.of<ProductsProvider>(context,listen:false).fetchAndSetCatProducts(catid: _args.id, page: page);
     }
    }

    @override
    void dispose() {
        _product.clear();
        super.dispose();
    }

    @override
    Widget build(BuildContext context){

        _product =  Provider.of<ProductsProvider>(context).products;

        return Scaffold(
              body: _product.isEmpty? WidgetOne() : ProductWidget()
        )

    }

}
问题根因
  1. 数据清空时机完全错误。旧详情页的dispose生命周期执行时间晚于新详情页的首次渲染时间:新页面push入栈时会先执行新页面的initState、完成首次build渲染,之后才会执行旧页面的dispose逻辑。在旧页销毁时才清空列表,新页第一次渲染时早就从Provider里读到了残留的旧数据,直接就把旧数据渲染到页面上了。
  2. 新数据拉取存在不必要的延迟。initState里用Future.delayed(Duration.zero)包裹拉取逻辑,这个异步任务会等当前帧渲染完成才执行,等于新页面第一次build的时候,新分类的数据拉取根本还没触发,自然只能读到旧数据。
  3. 冗余的本地状态字段增加了状态同步风险。State里定义的_product只是对Provider中全局列表的引用,本地持有这个字段没有实际作用,反而容易因为引用传递问题出现清空操作不生效的情况。
修复方案
  • 把旧数据清空逻辑从dispose迁移到数据拉取方法的入口处:触发新分类数据请求前,先清空Provider中存储的旧商品列表,立刻通知监听方刷新,保证页面首次渲染时拿到的是空状态,不会展示旧数据。
  • 去掉无意义的Future.delayed,改用addPostFrameCallback获取路由参数后直接触发拉取,减少不必要的时序延迟;如果业务允许,直接把分类id通过页面构造函数传递,完全可以避免路由参数获取的时序问题。
  • 删除State中冗余的_product字段,直接在build方法中从Provider读取最新数据即可,不需要在本地缓存引用。

修正后页面代码

class _CategoryDetailsScreenState extends State<CategoryDetailsScreen> {
    // 保留原有分页参数
    int page = 1;

    @override
    void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) {
            final args = ModalRoute.of(context)!.settings.arguments as CategoryDetailsScreenArgs;
            Provider.of<ProductsProvider>(context, listen: false)
                .fetchAndSetCatProducts(catid: args.id, page: page);
        });
    }

    // 移除dispose中清空列表的无效逻辑

    @override
    Widget build(BuildContext context) {
        // 直接从Provider读取最新数据,不存本地字段
        final productList = Provider.of<ProductsProvider>(context).products;
        return Scaffold(
            body: productList.isEmpty ? const WidgetOne() : const ProductWidget(),
        );
    }
}

Provider拉取方法补充逻辑

Future<void> fetchAndSetCatProducts({required int catid, required int page}) async {
    // 请求发起前先清空旧数据,通知页面刷新为空状态
    products.clear();
    notifyListeners();

    // 保留原有接口请求、解析新数据、赋值products、notifyListeners的逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:09:16