【问题标题】:When do I use setState in Flutter?什么时候在 Flutter 中使用 setState?
【发布时间】:2018-12-19 08:28:21
【问题描述】:

作为 Flutter 的新手,在 Flutter 应用程序中使用 setState 让我非常困惑。在下面的代码中,布尔值searching 和变量resBodysetState 内部使用。我的问题是为什么只有searchingresBody 在setState 中?为什么其他变量不可变?

var resBody;
bool searching =  false,api_no_limit = false;
String user = null;

Future _getUser(String text) async{
setState(() {
  searching = true;
});
user = text;
_textController.clear();
String url = "https://api.github.com/users/"+text;
  var res = await http
      .get(Uri.encodeFull(url), headers: {"Accept": 
           "application/json"});
  setState(() {
    resBody = json.decode(res.body);
  });
}

【问题讨论】:

标签: android dart flutter


【解决方案1】:

根据docs

调用 setState 会通知框架此对象的内部状态已发生更改,可能会影响此子树中的用户界面,这会导致框架为此 State 对象安排构建。

因此,如果小部件的状态发生变化您必须调用setState 来触发视图的重建并立即看到新状态所暗示的变化。

无论如何,下面的 sn-ps 是等价的。

第一种情况(直接形成flutter create <myproject>):

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

  void _incrementCounter() {

    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

第二种情况:

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

  void _incrementCounter() {
    _counter++;
    setState(() {});
  }

我不知道为什么,如果第一种情况是使用setState 的常规方式,我会说是因为代码的可读性。

【讨论】:

  • 问题是,很多人都在问同样的问题,为什么第一种方法是约定。文档说 “通常建议 setState 方法仅用于包装对状态的实际更改,而不是任何可能与更改相关联的计算。” 但是如果我的更改是我从 base64 字符串中读取的大型高清图像?如果图像的读取和转换在此之前完成,我在setState() 中放了什么?
【解决方案2】:

当您更改有状态小部件的状态时,请使用 setState() 重新构建小部件及其后代。
您无需在构造函数中调用setState() 或小部件的initState(),因为build() 无论如何都会在之后运行。

也不要在build() 内的同步代码中调用setState()。您不需要在 build() 内重新运行 build()

【讨论】:

  • 我很确定他的问题是关于“为什么我们不在 setState 回调中计算所有内容?”
【解决方案3】:

如果你看setState的实现:

  void setState(VoidCallback fn) {
    assert(fn != null);
    assert(...);
    final dynamic result = fn() as dynamic;
    assert(...);
    _element.markNeedsBuild();
  }

您会看到它所做的唯一事情是:断言一些事情以帮助您调试它的不正确使用、执行回调以及标记元素以便重建。

因此,从技术上讲,只要调用 setState 就可以更改 setState 回调内部或外部的某些变量。

但是,为了可读性,有很大的不同。重建小部件会影响应用程序的性能,因此您希望尽可能少地这样做。对需要在 setState 回调中重建小部件的变量进行所有(且仅是那些)更改,可以让人们(包括你未来的自己)清楚地知道为什么需要重建。

【讨论】:

    【解决方案4】:

    当您需要更改任何小部件在屏幕上显示的值时。例如,在应用程序中有一个任务。完成后应将哪些积分添加到“钱包”中。但问题是我们需要刷新应用才能看到“钱包”上的积分。为了解决这个问题,我们在 Button Onpressed() 上使用 Setstate()

    例如:

    RaisedButton(
     
     onpressed(){
        
       setstate(){
          
         points+10;
    
       }
     }
    
    )
    

    每次按下按钮时,它都会使用“wallet”变量返回的新值刷新小部件,而无需重新启动整个应用程序。

    【讨论】:

      【解决方案5】:

      根据documentations

      一般建议setState方法只用于 包装对状态的实际更改,而不是任何可能的计算 与变化相关联。例如,这里使用的值 build 函数递增,然后将更改写入 磁盘,但只有增量包含在setState

      Future<void> _incrementCounter() async {
        setState(() {
          _counter++;
        });
        Directory directory = await getApplicationDocumentsDirectory();
        final String dirName = directory.path;
        await File('$dir/counter.txt').writeAsString('$_counter');
      }
      

      【讨论】:

      • 嗯,但是 _counter++ 增量不是计算本身吗?
      【解决方案6】:

      每当您想要更新小部件树(通常包含一些新数据)时,您都可以调用setState。它只能在State 类中使用。这是简单的实现:

      class _MyPageState extends State<MyPage> {
        int _count = 0;
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: Center(
              child: RaisedButton(
                onPressed: () => setState(() => _count++),
                child: Text('Count = $_count'),
              ),
            ),
          );
        }
      }
      

      【讨论】:

        【解决方案7】:

        setState() 仅与 statefulWidget 内部颤振一起使用。当setState() 中定义的内容发生变化时,setState() 告诉颤振重建页面。

        NOT:setState() 是一个回调函数。

        Text(questions[questionIndex])
        

        这里我想根据给定的问题数组更改文本,并且在每次单击按钮时,我想将索引增加 1。

        void answerQuesion() {
            setState(() {
              questionIndex = questionIndex + 1;
            });
            print(questionIndex);
          }
        

        所以,我必须把这个索引增量放在setState() 中,这样flutter 会在每次更改questionIndex 后重建页面。

        【讨论】:

          猜你喜欢
          • 2020-06-14
          • 2012-07-29
          • 1970-01-01
          • 2019-12-29
          • 2012-03-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多