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

传入相同Key后Widget仍重建的原因探究

问题:传入相同Key后,为何仍会重新创建FooPage实例?

最小可复现代码

import 'dart:math' as math;
import 'package:flutter/material.dart';

class MainScreen extends StatefulWidget {
  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(onPressed: () => setState(() {})),
      body: FooPage(key: ValueKey(0)),
    );
  }
}

class FooPage extends StatelessWidget {
  FooPage({super.key});
  final int _number = math.Random().nextInt(100);

  @override
  Widget build(BuildContext context) {
    print('number = $_number');
    return Container();
  }
}

问题描述

每次点击FAB触发setState后,控制台都会输出新的number值。明明已经给FooPage传入了固定的ValueKey(0),为什么MainScreen的build方法还是会创建新的FooPage实例,而不是复用已有的那个?

注意

请勿提供以下解决方案:在FooPage中声明const构造函数并使用const FooPage(),或者将FooPage实例赋值为MainScreen的final成员变量。


解答

你混淆了Widget实例创建和Element树复用的核心逻辑:

  1. Widget实例必然会重建:每次调用setState,MainScreen的build方法都会重新执行,FooPage(key: ValueKey(0))这行代码会直接生成一个新的FooPage Widget实例——这是build方法执行的必然结果,和Key无关。

  2. Key管的是Element复用:Key的作用是给Flutter的Element树做唯一标识。当Widget树更新时,Flutter会对比新旧Widget的Key和类型,如果两者都匹配,就会复用对应的Element对象,不会重新创建Element。但Element复用的逻辑是:把新的Widget实例关联到已有Element上,然后调用这个新Widget的build方法。

  3. _number属于Widget实例:你的_number是FooPage Widget实例的成员变量,每次新的FooPage实例创建时,_number都会被重新赋值为随机数。Element复用后,会调用这个新Widget实例的build方法,所以控制台会打印新的number值。

总结:Key确保了Element不会被重建,但管不了Widget实例的创建——你每次build都生成新的Widget,_number自然跟着新实例变成随机值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:55:18