什么时候在 Flutter 中使用 setState?
Posted
技术标签:
【中文标题】什么时候在 Flutter 中使用 setState?【英文标题】:When do I use setState in Flutter? 【发布时间】:2018-12-19 08:28:21 【问题描述】:作为 Flutter 的新手,在 Flutter
应用程序中使用 setState
让我非常困惑。在下面的代码中,布尔值searching
和变量resBody
在setState
内部使用。我的问题是为什么只有searching
和resBody
在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);
);
【问题讨论】:
这取决于代码在小部件内部或外部的位置。从您的问题无法得出。 有什么好的资源来了解这个主题吗? docs.flutter.io/flutter/widgets/State/setState.html, flutterbyexample.com/stateful-widget-lifecycle。我确定有几个教程和 YouTube 视频,但我手头没有链接。我发现youtube.com/watch?v=RS36gBEp8OI 的介绍很好。 简单来说,当你改变变量的值时。这是最基本的。 但用户变量不在 setState 内,但它仍在应用程序内工作。那么它在 StatefulWidget 中是如何工作的呢? @goops17 【参考方案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 后重建页面。
【讨论】:
以上是关于什么时候在 Flutter 中使用 setState?的主要内容,如果未能解决你的问题,请参考以下文章
Flutter setStatus为什么有时候需要使用 mounted
Flutter :setState() 或 markNeedsBuild() 在构建期间调用
为啥 Flutter 中的 BloCListener 不保存状态,认证过程中出现 setState() 问题?