【问题标题】:setState not updating variable when declared on initState在 initState 上声明时 setState 不更新变量
【发布时间】:2021-02-15 20:42:53
【问题描述】:

我遇到了 Flutter 的问题:我有一个 navbar,它根据所选项目返回一个名为 Index 的整数。然后这个索引通过一个 List 来获取 Scaffold 的 body 的内容,一个 Widget() 类的对象。

默认主体是HomePage() 的对象,它有一个名为rpm 的整数参数。默认情况下,HomePage() 应该是显示的正文,因此,由于它取决于rpm 参数,我在initState 上声明rpm 参数。我还有一个 setState 可以动态更改 rpm

奇怪的是:如果我在 initState 中声明 List<Widgets> bodyListsetState 似乎不起作用。但是,如果我在构建方法中声明List<Widgets> bodyList,我可以看到HomePage() 的内容随着rpm 而动态变化。

代码摘录。不工作:

class _ScreenTreeState extends State<ScreenTree> {
  int _index;
  int _rpm;
  List<Widget> bodyList;

  @override
  void initState() {
    _isPlaying = false;
    _rpm = 0;
    _index = 0;
    bodyList = [
      HomePage(rpm: _rpm),
      StatisticsScreen(),
      WeightScreen(),
      SettingsPage()
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(...

工作:

class _ScreenTreeState extends State<ScreenTree> {
  int _index;
  int _rpm;
  List<Widget> bodyList;

  @override
  void initState() {
    _isPlaying = false;
    _rpm = 0;
    _index =
        0;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    bodyList = [
      HomePage(rpm: _rpm),
      StatisticsScreen(),
      WeightScreen(),
      SettingsPage()
    ];
    
    return Scaffold(...

我的理论是,这可能与以下事实有关:如果 _rpm 被声明为整数,Dart 会将其读取为基元而不是整数类的对象,因此如果在 initState 上声明,我实际上不是在传递一个对象,而是一个原语。但是我不明白为什么在build 方法中声明它会起作用。

我觉得这无关紧要,但如果有人需要,这里是更新_rpm 值的代码。请不要对此进行过多解读,因为我觉得它实际上并不相关,而且可能会分散注意力和混淆,而不是帮助:

onPressed: () {
          if (_isPlaying) {
            setState(() {
              _isPlaying = false;
            });
            Provider.of<MicrophoneEngine>(context, listen: false)
                .stopRecording();
          } else {
            setState(() {
              _isPlaying = true;
            });
            Provider.of<MicrophoneEngine>(context, listen: false)
                .startRecording((rpmCall) {
              setState(() {
                _rpm = rpmCall;
              });
            });
          }
        },

【问题讨论】:

  • 除非您真的知道自己在做什么,否则不要将小部件存储在您的状态中。始终确保为每次调用 build 创建新的小部件对象。

标签: flutter dart setstate


【解决方案1】:

保留小部件的引用是一种不好的做法(就像在第一个示例中一样),事实上,您根本不需要那个 List。

每次使用setState 时,都会重新构建小部件并传递新值。在第一个示例中,您每次都从 init 传递 HomePage(rpm: _rpm),这就是它不更新的原因。意思是,您不会使用更新后的值重建 HomePage,您只需从 initState 中传递 HomePage,它是使用初始 _rpm0 实例化的。

【讨论】:

  • 不错的答案!但是,将小部件存储在状态中并不是一定不好的做法,但它经常会导致初学者感到困惑。
  • 恕我直言,绝对没有必要保留对小部件的引用。他没有在构建中使用 List,但他在 initState 中使用它,这就是问题所在。
  • 我完全理解问题所在。但是,通过将小部件存储在状态中而不是在重建时实例化新小部件,有可能获得性能优势。
  • @YoBo 所以,如果我做对了,setState 只会重建 build 方法中的变量,对吧? initState 中的变量根本不会改变。另外,如果没有列表,您将如何更改内容?这对我来说似乎是最直接的事情。
  • @ChristopherMoore 感谢您的后见之明。是的,我是初学者。此外,虽然您在性能方面可能是对的,但 Flutter(甚至 Dart)是否适合这种有意义的 HPC 场景类型?。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
相关资源
最近更新 更多