Flutter登录页与主页切换异常:非手动热重载无法显示页面
Flutter Login/Home Page Auto-Switch Issue Fix
Hey there, let's break down why your login and home pages aren't switching automatically and fix this step by step.
The Root Cause
Looking at your code, two key issues are causing this problem:
- Asynchronous Storage Initialization: Your
StorageUtil.getInstance()is an async operation, but you're callingrunApp()immediately after it without waiting for it to complete. When theWrapperfirst builds, the storage hasn't finished initializing yet, soStorageUtil.getString('access_token')returnsnull—hence it shows the login page. Only when you hot reload, the storage is already initialized, so it reads the token correctly and shows the home page. - No State Refresh on Token Update: After a successful login, you store the token but don't trigger a rebuild of the
Wrappercomponent. That means it stays on the login page until you manually reload.
Fixed Code Examples
Step 1: Wait for Storage Initialization in Main
First, modify your main function to wait for the storage to finish initializing before running the app:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await StorageUtil.getInstance(); // Wait for storage to be ready runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: Wrapper(), ); } }
Step 2: Update Wrapper to Handle Token Changes
Rewrite the Wrapper to use a FutureBuilder for initial token loading, and add a way to refresh the state when the token is updated after login:
class Wrapper extends StatefulWidget { const Wrapper({super.key}); @override _WrapperState createState() => _WrapperState(); } class _WrapperState extends State<Wrapper> { late Future<String?> _tokenFuture; @override void initState() { super.initState(); // Fetch token once when the widget initializes _tokenFuture = Future.value(StorageUtil.getString('access_token')); } // Call this method to refresh the token state after login void _refreshToken() { setState(() { _tokenFuture = Future.value(StorageUtil.getString('access_token')); }); } @override Widget build(BuildContext context) { return FutureBuilder<String?>( future: _tokenFuture, builder: (context, snapshot) { // Show loading while we wait for the token if (snapshot.connectionState == ConnectionState.waiting) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } final token = snapshot.data; if (token != null && token.isNotEmpty) { print('filled $token'); return const Home(); } else { print('empty $token'); // Pass the refresh method to Authenticate so it can trigger a rebuild after login return Authenticate(onLoginSuccess: _refreshToken); } }, ); } }
Step 3: Trigger Refresh in Authenticate Component
Update your Authenticate component to call the refresh method once the login is successful and the token is stored:
// Inside your Authenticate widget, add a callback parameter class Authenticate extends StatelessWidget { final VoidCallback? onLoginSuccess; const Authenticate({super.key, this.onLoginSuccess}); // Example login button press handler void _handleLogin() async { // Perform your login API call here // ... // After successful login, store the token await StorageUtil.putString('access_token', 'your_new_token'); // Trigger the wrapper to refresh its state onLoginSuccess?.call(); } @override Widget build(BuildContext context) { return Scaffold( // Your login UI here body: Center( child: ElevatedButton( onPressed: _handleLogin, child: const Text('Login'), ), ), ); } }
Why This Works
- We wait for the storage to initialize before running the app, so the first token read is accurate.
- The
FutureBuilderhandles the initial loading state and ensures we only render the correct page once we have the token. - The
_refreshTokenmethod triggers a rebuild of theWrapperwhen the token is updated, so the page switches automatically after login without needing a hot reload.
内容的提问来源于stack exchange,提问作者Razvan Dumitrescu
相关产品推荐
相关产品推荐

