【问题标题】:Flutter setState causes infinite renderingFlutter setState 导致无限渲染
【发布时间】:2023-03-19 11:26:01
【问题描述】:
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();
    
    Future<User> getGoogleContent(UserRepository auth) async {
    var auth_user = await auth.getUser();
    print(auth_user.uid); //This print
    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) {
    UserRepository auth = Provider.of<UserRepository>(context);
    getGoogleContent(auth);

    void logout() async {
      await auth.signOut();
    }

    return  isLoading ? LoadingScreen() :  Scaffold(appBar:AppBar(title:Text("Giriş")), body: 
      IconButton(icon:Icon(Icons.signal_cellular_4_bar),onPressed: logout)
    );
  }
}

我想要做的是将我的用户数据保存到 firebase 并在执行此操作时显示加载屏幕。它可以工作,但是我的函数中的打印语句不断被无限调用。我知道它与 setState 有关,但我不明白为什么它会不断渲染和调用该函数。如果有人能告诉我为什么我一直在控制台中获取打印的用户 ID,我会很高兴。

【问题讨论】:

  • 规则 #1:不要在小部件中包含业务逻辑。
  • setState 每次都会触发 build 方法,所以把你的函数放在 initstate 中。

标签: flutter


【解决方案1】:

您当前在build 方法中调用getGoogleContent。调用 setState 会触发新的重建。由于您实际上是通过在getGoogleContent 中调用getGoogleContent 来在build 中调用setState,因此您创建了一个无限循环。

要解决这个问题,请将 getGoogleContent(auth); 移动到 initState 以便它只被调用一次并且重建不会再次触发此方法:

@override
void initState() {
  super.initState();
  getGoogleContent(auth);
}

虽然您当前在加载数据时显示加载屏幕的方法是有效的,但FutureBuilder 消除了您当前方法的大部分复杂性并防止发生此类错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多