Flutter-更新状态,然后导航离开

bq9c1y66  于 2023-01-02  发布在  Flutter
关注(0)|答案(2)|浏览(126)

我有一个名为AuthenticatingScreen的有状态小部件,我尝试在其中执行以下流程...
1.输出消息,让用户知道我们正在登录他们
1.获取用户oAuth令牌(调用服务文件)
1.更新消息以让用户知道我们正在加载他们的详细信息
1.获取用户详细信息并将其重定向离开
问题是,在第三步中,我正在重建状态,这反过来又导致build方法再次被触发,并再次调用服务,从而触发异常。

import 'package:flutter/material.dart';
import 'package:testing/services/auth_service.dart';

class AuthenticatingScreen extends StatefulWidget {
  final String token;

  AuthenticatingScreen(this.token);

  @override
  State<AuthenticatingScreen> createState() => _AuthenticatingScreenState();
}

class _AuthenticatingScreenState extends State<AuthenticatingScreen> {
  // step 1) our default message
  String _message = 'Please wait while we log you in...';

  Future<void> _fetchUserDetails() {
    return Future.delayed(const Duration(seconds: 3), () {
      // ToDo: fetch user details from the server
    });
  }

  @override
  Widget build(BuildContext context) {

    // step 2) get our oAuth token
    AuthService.handleCallback(widget.token).then((accessCode) async {
      
      // step 3) update our message
      setState(() => _message = 'We\'re just getting your details');

      // step 4) retrieve our user details and redirect away
      _fetchUserDetails().then((_) {
        Navigator.of(context).pushNamedAndRemoveUntil(
          '/home',
          (Route<dynamic> route) => false,
        );
      });
    });

    /// output our authenticating screen.
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.only(bottom: 20.0),
              child: CircularProgressIndicator(),
            ),
            Text(_message),
          ],
        ),
      ),
    );
  }
}

**我的问题是:**如何解决这个问题/提取这个逻辑,使其只在创建小部件时才触发,同时仍然可以访问构建上下文以进行导航?

我尝试过使小部件本身无状态化,并将消息和微调器提取到一个单独的小部件中,但仅更改输入参数仍然不能强制进行重建。

csbfibhn

csbfibhn1#

你可以这样做,我通常使用getx & controller来实现这一点。
1.最好在控制器中分离UI类和服务类
1.使UI类具有状态
1.在onInit()方法中调用API,因为它只调用一次,它将触发服务类
1.在API方法中,当您获得结果200时,启动UI转换

mbzjlibv

mbzjlibv2#

好的,我已经想出了解决方案。看起来在build()方法中进行服务调用是个坏主意。
将我的服务调用移到一个void函数中,然后可以在initState()方法中调用该函数,这似乎是一种可行的方法。

import 'package:flutter/material.dart';
import 'package:testing/screens/home.dart';
import 'package:testing/services/auth_service.dart';

class AuthenticatingScreen extends StatefulWidget {
  final String token;

  AuthenticatingScreen(this.token);

  @override
  State<AuthenticatingScreen> createState() => _AuthenticatingScreenState();
}

class _AuthenticatingScreenState extends State<AuthenticatingScreen> {
  /// the default message to display to the user.
  String _message = 'Please wait while we log you in...';

  void _authenticateUser(String token) {
    AuthService.handleCallback(widget.token).then((accessCode) async {
      // we've got the users token, now we need to fetch the user details
      setState(() => _message = 'We\'re just getting your details');

      // after fetching the user details, push them to the home screen
      _fetchUserDetails().then((_) {
        Navigator.of(context).pushNamedAndRemoveUntil(
          HomeScreen.name,
          (Route<dynamic> route) => false,
        );
      });
    });
  }

  Future<void> _fetchUserDetails() {
    return Future.delayed(const Duration(seconds: 3), () {
      // ToDo: fetch user details from the server
    });
  }

  @override
  void initState() {
    super.initState();
    _authenticateUser(widget.token);
  }

  @override
  Widget build(BuildContext context) {
    /// output our authenticating screen.
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.only(bottom: 20.0),
              child: CircularProgressIndicator(),
            ),
            Text(_message),
          ],
        ),
      ),
    );
  }
}

这样,当再次调用build()方法进行重建时,只需重新绘制很少的细节。

相关问题