Flutter setState是否应该在颤振窗口小部件中包含任何实体

Flutter setState是否应该在颤振窗口小部件中包含任何实体,flutter,Flutter,我正在审阅和it状态的文档 通知框架此对象的内部状态已更改 变了 我猜doc真的想强调这一点 通知框架该对象的内部状态已更改 变了 我用默认生成的代码尝试了一个空的setState,它能够触发通知 import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildCont

我正在审阅和it状态的文档

通知框架此对象的内部状态已更改 变了

我猜doc真的想强调这一点

通知框架该对象的内部状态已更改 变了

我用默认生成的代码尝试了一个空的setState,它能够触发通知

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    _counter++; // moved it out of setState
    setState(() {
//  _counter++; // instead setting it before setState
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“颤振演示”,
主题:主题数据(
主样本:颜色。蓝色,
),
主页:MyHomePage(标题:“颤振演示主页”),
);
}
}
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
int _计数器=0;
void _incrementCounter(){
_计数器+++;//已将其移出设置状态
设置状态(){
//_counter++;//而是在设置state之前设置它
});
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(widget.title),
),
正文:中(
子:列(
mainAxisAlignment:mainAxisAlignment.center,
儿童:[
正文(
“您已经按了这么多次按钮:”,
),
正文(
“$”计数器“,
样式:Theme.of(context).textTheme.display1,
),
],
),
),
浮动操作按钮:浮动操作按钮(
按下时:\ u递增计数器,
工具提示:“增量”,
子:图标(Icons.add),
),
);
}
}
上面的代码确实工作得很好,但我在internet上找到的所有示例都是显式更改值或使用setState执行某些活动,这真的有必要吗?

是的,它工作得很好

setState
中的回调没有像中所传达的那样具有魔力。它并没有被传递,而是在某个内部生命周期内被调用

提供的回调将立即同步调用。它不能返回未来(回调不能是异步的),因为这样就不清楚实际设置状态的时间

没有断言的源代码

它只是帮助您立即在闭包中执行代码,然后在下一帧中将其标记为重新生成。这就是全部。虽然它可以很好地处理空白回调,但这不是建议的做法

这可能与可维护性有关,因为
setState
中的所有内容都应该改变小部件的状态,明确地声明,没有任何意外。

Short:

(但当它体内有东西时,它会变得更容易阅读和理解,对吗?)

长版本:

颤振将检查一些条件,如回调不为空,断言当前小部件的状态,回调不能是异步的。。。 在MarkWidget需要重新构建之前,Flatter将在setState体内执行任何操作

@protected
  void setState(VoidCallback fn) {
    assert(fn != null);
    assert(() {
      if (_debugLifecycleState == _StateLifecycle.defunct) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called after dispose(): $this'),
          ErrorDescription(
            'This error happens if you call setState() on a State object for a widget that '
            'no longer appears in the widget tree (e.g., whose parent widget no longer '
            'includes the widget in its build). This error can occur when code calls '
            'setState() from a timer or an animation callback.'
          ),
          ErrorHint(
            'The preferred solution is '
            'to cancel the timer or stop listening to the animation in the dispose() '
            'callback. Another solution is to check the "mounted" property of this '
            'object before calling setState() to ensure the object is still in the '
            'tree.'
          ),
          ErrorHint(
            'This error might indicate a memory leak if setState() is being called '
            'because another object is retaining a reference to this State object '
            'after it has been removed from the tree. To avoid memory leaks, '
            'consider breaking the reference to this object during dispose().'
          ),
        ]);
      }
      if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called in constructor: $this'),
          ErrorHint(
            'This happens when you call setState() on a State object for a widget that '
            'hasn\'t been inserted into the widget tree yet. It is not necessary to call '
            'setState() in the constructor, since the state is already assumed to be dirty '
            'when it is initially created.'
          ),
        ]);
      }
      return true;
    }());
    final dynamic result = fn() as dynamic;
    assert(() {
      if (result is Future) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() callback argument returned a Future.'),
          ErrorDescription(
            'The setState() method on $this was called with a closure or method that '
            'returned a Future. Maybe it is marked as "async".'
          ),
          ErrorHint(
            'Instead of performing asynchronous work inside a call to setState(), first '
            'execute the work (without updating the widget state), and then synchronously '
           'update the state inside a call to setState().'
          ),
        ]);
      }
      // We ignore other types of return values so that you can do things like:
      //   setState(() => x = 3);
      return true;
    }());
    _element.markNeedsBuild();
  }
@受保护
无效设置状态(无效回调fn){
断言(fn!=null);
断言(){
if(\u debugLifecycleState==\u StateLifecycle.defunct){
从零件中抛出错误([
ErrorSummary('setState()在dispose()之后调用:$this'),
错误描述(
'如果对控件的状态对象调用setState(),则会发生此错误'
'不再出现在窗口小部件树中(例如,其父窗口小部件不再出现'
'将小部件包含在其内部版本中)。当代码调用时可能会发生此错误'
'来自计时器或动画回调的setState()
),
错误提示(
“首选解决方案是”
'要取消计时器或停止在dispose()中收听动画'
'回调。另一种解决方案是检查此函数的“mounted”属性'
'在调用setState()以确保对象仍在
“树。”
),
错误提示(
'如果调用setState(),此错误可能表示内存泄漏'
'因为另一个对象保留对此状态对象的引用'
'从树中删除后。为避免内存泄漏,'
'考虑在dispose()期间中断对此对象的引用。'
),
]);
}
if(_debugLifecycleState==_StateLifecycle.created&&!mounted){
从零件中抛出错误([
ErrorSummary('setState()在构造函数中调用:$this'),
错误提示(
'当您对一个控件的状态对象调用setState()时,就会发生这种情况'
'尚未插入小部件树。无需调用'
构造函数中的“setState(),因为该状态已假定为脏”
“当它最初创建时。”
),
]);
}
返回true;
}());
最终动态结果=fn()为动态;
断言(){
如果(结果是未来){
从零件中抛出错误([
ErrorSummary('setState()回调参数返回了一个未来值'),
错误描述(
'调用$this上的setState()方法时使用的闭包或方法为'
'返回了一个未来。可能它被标记为“异步”。'
),
错误提示(
'不是在对setState()的调用中执行异步工作,而是首先'
'执行工作(不更新小部件状态),然后同步'
'更新对setState()的调用中的状态。'
),
]);
}
//我们忽略其他类型的返回值,以便
You can call setState with an empty body. 
@protected
  void setState(VoidCallback fn) {
    assert(fn != null);
    assert(() {
      if (_debugLifecycleState == _StateLifecycle.defunct) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called after dispose(): $this'),
          ErrorDescription(
            'This error happens if you call setState() on a State object for a widget that '
            'no longer appears in the widget tree (e.g., whose parent widget no longer '
            'includes the widget in its build). This error can occur when code calls '
            'setState() from a timer or an animation callback.'
          ),
          ErrorHint(
            'The preferred solution is '
            'to cancel the timer or stop listening to the animation in the dispose() '
            'callback. Another solution is to check the "mounted" property of this '
            'object before calling setState() to ensure the object is still in the '
            'tree.'
          ),
          ErrorHint(
            'This error might indicate a memory leak if setState() is being called '
            'because another object is retaining a reference to this State object '
            'after it has been removed from the tree. To avoid memory leaks, '
            'consider breaking the reference to this object during dispose().'
          ),
        ]);
      }
      if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called in constructor: $this'),
          ErrorHint(
            'This happens when you call setState() on a State object for a widget that '
            'hasn\'t been inserted into the widget tree yet. It is not necessary to call '
            'setState() in the constructor, since the state is already assumed to be dirty '
            'when it is initially created.'
          ),
        ]);
      }
      return true;
    }());
    final dynamic result = fn() as dynamic;
    assert(() {
      if (result is Future) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() callback argument returned a Future.'),
          ErrorDescription(
            'The setState() method on $this was called with a closure or method that '
            'returned a Future. Maybe it is marked as "async".'
          ),
          ErrorHint(
            'Instead of performing asynchronous work inside a call to setState(), first '
            'execute the work (without updating the widget state), and then synchronously '
           'update the state inside a call to setState().'
          ),
        ]);
      }
      // We ignore other types of return values so that you can do things like:
      //   setState(() => x = 3);
      return true;
    }());
    _element.markNeedsBuild();
  }