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

Flutter GetX跳转不同ID商品详情页无法加载新数据

问题分析与解决方案

问题根源

GetX默认会复用已存在的ProductDetailsController实例,当你通过Get.toNamed打开同一个路由且设置preventDuplicates: false时,控制器的onInit方法仅在第一次初始化时执行,后续跳转不会重新读取新传入的product_id,导致新页面展示旧数据。同时视图中Get.create的使用方式也会造成控制器实例管理混乱,无法响应参数变化。


解决方案

方案一:监听路由参数变化,触发数据重载

修改ProductDetailsController,添加路由参数监听逻辑,确保参数更新时重新加载数据:

class ProductDetailsController extends GetxController {
  WebViewController? webViewController;
  var webViewHeight = 100.0.obs;
  var productDetailsLoading = true.obs;
  var productDetails = <String, dynamic>{}.obs;
  var productId = 0.obs;

  @override
  void onInit() {
    super.onInit();
    // 初始化时读取参数并加载数据
    _updateProductIdAndLoad();
    // 监听路由变化,当前页面为商品详情页时重新检查参数
    ever(Get.routing, (route) {
      if (route.current == Routes.PRODUCT_DETAILS) {
        _updateProductIdAndLoad();
      }
    });
  }

  void _updateProductIdAndLoad() {
    final newProductId = Get.arguments?['product_id'] ?? 0;
    // 仅当商品ID变化时才重新加载
    if (newProductId != productId.value) {
      productId.value = newProductId;
      loadPage();
    }
  }

  // 以下原有方法保持不变...
}

方案二:每次跳转创建独立控制器实例

通过Binding机制,让每次进入商品详情页时都创建新的控制器实例:

  1. 创建绑定类
class ProductDetailsBinding extends Bindings {
  @override
  void dependencies() {
    Get.put(ProductDetailsController());
  }
}
  1. 修改路由配置
GetMaterialApp(
  initialRoute: Routes.HOME,
  getPages: [
    // 其他路由...
    GetPage(
      name: Routes.PRODUCT_DETAILS,
      page: () => const ProductDetailsView(),
      binding: ProductDetailsBinding(),
      preventDuplicates: false,
    ),
  ],
);
  1. 清理视图中的控制器创建代码
class ProductDetailsView extends GetView<ProductDetailsController> {
  const ProductDetailsView({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    // 移除这一行:Get.create<ProductDetailsController>(() => ProductDetailsController());
    return Obx(() {
      if (controller.productDetailsLoading.value) {
        return Material(
          color: isDarkMode()
              ? DynamicColorsCollection.backgroundColorSecondaryDark
              : DynamicColorsCollection.backgroundColorSecondaryLight,
          child: LoadingShimmer(),
        );
      }
      return CustomScaffold(
        backgroundColor: isDarkMode()
            ? DynamicColorsCollection.backgroundColorDark
            : DynamicColorsCollection.backgroundColorLight,
        // 其余视图代码...
      );
    });
  }
}

跳转代码保持原有逻辑即可,Binding会自动为新页面创建独立控制器实例。

方案三:手动管理控制器实例(简单场景适用)

跳转时手动删除旧控制器,确保新页面使用全新实例:

Get.toNamed(
  Routes.PRODUCT_DETAILS,
  arguments: {
    "product_id": id,
  },
  preventDuplicates: false,
)?.then((_) {
  // 返回时清理控制器,避免内存占用
  Get.delete<ProductDetailsController>();
});

同时修改视图中的控制器创建方式:

class ProductDetailsView extends GetView<ProductDetailsController> {
  const ProductDetailsView({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    Get.put(ProductDetailsController());
    return Obx(() {
      // 其余代码不变...
    });
  }
}

方案选择建议

  • 方案一适合需要复用控制器、减少资源消耗的场景,仅在参数变化时重载数据;
  • 方案二更适合需要完全隔离每个页面状态的场景,每个商品详情页拥有独立的控制器实例;
  • 方案三适合小型项目或简单页面,手动管理实例逻辑更直接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:40:16