调用notifyListeners后Widget未重建,登录后无法访问NavigationRail全部页面
问题分析与解决方案
核心问题
你在login函数中新建了一个独立的LoginProvider实例,而UI层(main.dart)监听的是ChangeNotifierProvider创建的另一个实例。两者完全独立,所以调用notifyListeners()只会通知这个新实例的监听者,不会触发UI层的重建。
修改步骤
1. 提升Provider的作用域
把ChangeNotifierProvider移到MyHomePage之外,确保整个应用中只有一个LoginProvider实例,避免每次build时重建Provider。
修改main.dart的根组件部分:
void main() { runApp( ChangeNotifierProvider( create: (context) => LoginProvider(), child: const MyApp(), ), ); } // 保留原MyApp和MyHomePage结构,移除MyHomePage内部的ChangeNotifierProvider
2. 在login函数中获取全局的Provider实例
不要新建LoginProvider,而是通过Provider.of获取已存在的实例。修改login.dart中的login函数:
void login(String userName, String passWord, BuildContext context) async { Response response; Dio dio = Dio(); dio.interceptors.add(InterceptorsWrapper( onResponse: (response, handler) { var token = getToken.Transcribe(response.data); // 获取全局的LoginProvider实例,listen: false表示仅修改状态不监听 final loginProvider = Provider.of<LoginProvider>(context, listen: false); loginProvider.providestate(true); print(token); print("logged in"); handler.next(response); }, )); try { // Http Post method } catch (e) { print(e); } }
注意:调用
login时需要传入能找到Provider的BuildContext(比如从登录页面的按钮点击事件中获取)。
3. 调整MyHomePage中的NavigationRail代码
移除MyHomePage内部的ChangeNotifierProvider,直接使用全局的Provider:
class MyHomePageState extends State<MyHomePage> { var selectedIndex = 0; List<Widget> pages = [Page0(), Page1(), Page2(), Placeholder()]; @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constraints) { return Scaffold( body: Row( children: [ SafeArea( child: Consumer<LoginProvider>( builder: (context, provider, child) { return NavigationRail( extended: constraints.maxWidth >= 600, minExtendedWidth: 200, destinations: const [ NavigationRailDestination(icon: Icon(Icons.home), label: Text("首页")), NavigationRailDestination(icon: Icon(Icons.pageview), label: Text("页面1")), NavigationRailDestination(icon: Icon(Icons.pageview), label: Text("页面2")), NavigationRailDestination(icon: Icon(Icons.settings), label: Text("设置")), ], selectedIndex: selectedIndex, onDestinationSelected: (value) { if (provider.loginstate) { setState(() { selectedIndex = value; }); print("On"); } else { if (value == 0 || value == 3) { setState(() { selectedIndex = value; }); print("OFF"); } } }, ); }, ), ), Expanded( child: Scaffold( body: IndexedStack( index: selectedIndex, children: pages, ), ), ), ], ), ); }); } }
额外注意事项
- 确保调用
login时传入的BuildContext处于Provider的作用域内。 - 如果需要在无上下文环境访问Provider,可以使用
GlobalKey来获取应用级上下文。
内容的提问来源于stack exchange,提问作者TELYD1996
相关产品推荐
相关产品推荐

