Flutter setState引发无限渲染问题求助
为什么你的UID会被无限打印?
你遇到的问题根源在于**getGoogleContent被直接放在了build方法里调用**,这和Flutter的组件渲染逻辑、setState的作用形成了无限循环链,具体过程是这样的:
- 组件首次渲染时,
build方法执行,调用getGoogleContent(auth) getGoogleContent是异步方法,完成用户数据保存后调用了setState(() { isLoading = false; })setState会通知Flutter框架:组件状态发生变化,需要重新执行build方法更新UI- 新的
build方法执行时,又会再次调用getGoogleContent(auth),重复上述步骤 - 循环往复之下,
print(auth_user.uid)就会被无限次执行,控制台自然会不断打印UID
解决方案:打破循环,把异步调用移到单次执行的生命周期里
要解决这个问题,你需要把getGoogleContent的调用移到只会执行一次的组件生命周期方法中,比如initState——这个方法仅在组件初始化时运行一次,不会因为setState触发的重建而重复执行。
修改后的完整代码如下:
import 'package:flutter/material.dart'; import 'package:myfitnesstrainer/logic/firestore_services.dart'; import 'package:myfitnesstrainer/models/user.dart'; import 'package:myfitnesstrainer/models/user_repository.dart'; import 'package:myfitnesstrainer/screens/loading_screen.dart'; import 'package:provider/provider.dart'; class DistributePage extends StatefulWidget { // final User currentUser; const DistributePage(); @override _DistributePageState createState() => _DistributePageState(); } class _DistributePageState extends State<DistributePage> { FirestoreServices _firestoreServices = new FirestoreServices(); bool isLoading=true; User curUser= new User(); @override void initState() { super.initState(); // 用addPostFrameCallback确保context已准备就绪,再获取Provider WidgetsBinding.instance.addPostFrameCallback((_) { final auth = Provider.of<UserRepository>(context, listen: false); getGoogleContent(auth); }); } Future<User> getGoogleContent(UserRepository auth) async { final auth_user = await auth.getUser(); print(auth_user.uid); // 现在只会打印一次啦 curUser.userID = auth_user.uid; curUser.name = auth_user.displayName; curUser.email = auth_user.email; curUser.imageUrl = auth_user.photoUrl; curUser = await _firestoreServices.saveUser(curUser); setState(() { isLoading = false; }); return curUser; } @override Widget build(BuildContext context) { void logout() async { // 退出登录不需要监听状态变化,所以listen设为false优化性能 await Provider.of<UserRepository>(context, listen: false).signOut(); } return isLoading ? LoadingScreen() : Scaffold( appBar: AppBar(title: const Text("Giriş")), body: IconButton( icon: const Icon(Icons.signal_cellular_4_bar), onPressed: logout ) ); } }
关键修改点说明:
- 把异步调用移到
initState:确保getGoogleContent仅执行一次,彻底打破循环 Provider.of添加listen: false:在不需要监听状态变化的场景下使用,避免不必要的组件重建,提升性能- 移除
build里的getGoogleContent调用:从根源上避免每次重建都触发异步操作
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

