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

Flutter Widget中如何将函数返回的Future类型结果赋值给变量

问题根本原因
  • build方法是高频调用的,你在里面执行setJsessionId,函数内部的setState会触发Widget重建,重建又会再次执行setJsessionId,形成死循环,导致无限调用认证接口。
  • FutureBuilder的future参数直接传入getTasks(),每次build都会生成新的Future实例,触发重复请求,加上ListTile使用UniqueKey每次重建都会生成新的key,导致列表项无限重复渲染。
解决方案

步骤1:将异步初始化逻辑放到Widget生命周期回调中

使用StatefulWidget的initState方法执行sessionId初始化,该方法只会在Widget第一次创建时执行一次,只要Widget不销毁重建就不会重复触发:

class YourPageState extends State<YourPage> {
  String? jsessionId;
  late Future<List<Task>> _tasksFuture; // 提前缓存任务列表的Future实例

  @override
  void initState() {
    super.initState();
    _initSessionAndData();
  }

  Future<void> _initSessionAndData() async {
    // 仅执行一次认证请求
    jsessionId = await getJsessionId();
    // 拿到sessionId后初始化任务请求的Future
    _tasksFuture = getTasks(jsessionId!);
    // 仅触发一次重建
    setState(() {});
  }

步骤2:修复FutureBuilder和列表渲染逻辑

使用提前缓存的Future实例,同时替换掉UniqueKey避免列表强制重绘:

@override
Widget build(BuildContext context) {
  return Scaffold(
    // 其他布局代码省略
    child: jsessionId == null 
      // sessionId未获取到前展示加载态
      ? const Center(child: CircularProgressIndicator())
      : FutureBuilder<List<Task>>(
          // 传入缓存的Future实例,不会重复发起请求
          future: _tasksFuture,
          builder: (BuildContext context, AsyncSnapshot<List<Task>> snapshot){
            if(snapshot.hasError){
              return const Text('Erreur');
            }
            if(snapshot.hasData){
              // 直接使用snapshot返回的数据,避免和外部变量混淆导致重复
              final taskList = snapshot.data!;
              return ReorderableListView(
                buildDefaultDragHandles: false,
                header: Center(
                  child: Container(
                    child: Text(
                      'Listes des tâches',
                      style: Theme.of(context).textTheme.headline5,
                    ),
                    padding: EdgeInsets.symmetric(vertical: 20)
                  )
                ),
                children: taskList.map((e) => ListTile(
                  // 使用任务自身的唯一标识作为key,不要用UniqueKey
                  key: ValueKey(e.id), // 假设Task类存在唯一的id字段
                  leading: Image.asset("assets/images/Task-Bleu_0.png", height: 30),
                  title: Text("Tache: " + e.name),
                  subtitle: Text("Projet: " + e.projectName),
                  trailing: Wrap(
                    spacing: 5,
                    children: [
                      Image.asset("assets/images/Task-Validated_0.png", height: 30),
                      GestureDetector(
                        onTap: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => TaskInfoPage(task: e)
                            ),
                          );
                        },
                        child: Icon(BeoticIcons.simply_right, size: 28)
                      )
                    ]
                  )
                )).toList(),
                onReorder: _onReorder,   
              );
            }
            return const Center(child: CircularProgressIndicator());
          }
        )
  );
}

额外优化建议

如果sessionId是全应用通用的,可以将它存储到全局单例、状态管理容器(如Provider、GetX)中,整个应用生命周期只请求一次,无需每个页面重复获取认证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:24:10