首页 > 解决方案 > 提供者登录注销颤动

问题描述

我正在尝试使用 Provider 创建一个简单的身份验证流程。我有三页:

  1. 登录页面
  2. 入职页面
  3. 主页

这个应用程序的流程是:

  1. 如果用户第一次打开应用程序,他/她将被重定向到入职页面,然后登录到主页。
  2. 对于第二次使用的用户,应用程序首先检查登录状态并重定向到登录 -> 主页或直接到主页。

这是我在代码中的设置:

主要.dart

void main() {
  runApp(MultiProvider(providers: [
    ChangeNotifierProvider<StorageHelper>(create: (_) => StorageHelper()),
    ChangeNotifierProvider<AuthProvider>(create: (_) => AuthProvider()),
  ], child: MyApp()));
}

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    return Consumer<AuthProvider>(builder: (final BuildContext context,
        final AuthProvider authProvider, final Widget child) {
        print(authProvider.isAuthenticated); // this is false whenever I //click the logout from category(or other pushed pages) but the below ternary //operation is not executing
      return MaterialApp(
          title: 'My Poor App',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primaryColor: Color(0xff29c17e),
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: authProvider.isAuthenticated ? HomeScreen() : LoginScreen(),
          onGenerateRoute: Router.onGenerateRoute,
        );
    });
  }
}

登录界面.dart

class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final authProvider = Provider.of<AuthProvider>(context, listen: false);
    return Scaffold(
      body: Center(
          child: MaterialButton(
              onPressed: () async {
                await authProvider.emailLogin('user@email.com', 'pass');
              },
              child: Text('Login'))),
    );
  }
}

HomeScreen.dart

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final auth = Provider.of<AuthProvider>(context, listen: false);
    return Scaffold(
      body: Center(
        child: MaterialButton(
                elevation: 2,
                onPressed: () {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => CategoryScreen()));
                },
                child: Text('Reset')),
      ),
    );
  }
}

AuthProvider.dart

class AuthProvider extends ChangeNotifier {
  bool _isAuthenticated = false;

  bool get isAuthenticated => _isAuthenticated;

  set isAuthenticated(bool isAuth) {
    _isAuthenticated = isAuth;
    notifyListeners();
  }

  Future emailLogin(String email, String password) async {
    isAuthenticated = true;
  }

  Future logout() async {
    isAuthenticated = false;
  }
}

如果我从主页注销使用Provider.of<AuthProvider>(context).logout()它工作正常。但是,如果我pushpushReplacement新路由并尝试从新路由注销(只是说我从主页导航到类别页面并尝试从那里注销),我不会被重定向到 LoginPage。如果我打印它的值,isAuthenticated它会打印 false 但消费者没有听或至少没有对变量更改做出反应。

请不要将此问题标记为重复,我已经搜索了许多其他类似的问题,但没有一个适合我的案例。

编辑: CategoryScreen.dart

class CategoryScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: RaisedButton(
          onPressed: () {
            final auth = Provider.of<AuthProvider>(context, listen: false);
            auth.logout();
            // print(auth.isAuthenticated);
          },
          child: Text('Category Logout'),
        ),
      ),
    );
  }
}

首次登录页面小部件树

主页的小部件树

navigator.pushAndRemoveUntil(CategoryScreen) 之后的小部件树

标签: flutterflutter-providerstate-management

解决方案


我猜你的问题是你没有使用Consumerfor logout, in your homein MaterialApp。看看,如果它适合你

主要.dart

// needs to listen to the changes, to make changes 
home: Consumer<AuthProvider>(
  builder: (context, authProvider, child){
     return authProvider.isAuthenticated ? HomeScreen() : LoginScreen();
  }
)

由于,Consumer不存在于您的home, 即使值被更改, 它也无法根据提供者为您更新视图。


推荐阅读