Flutter go_router结合Provider传Auth数据报实例成员访问错误
问题描述
项目中采用Provider方案实现状态管理,需要将Auth鉴权提供者的状态信息共享给go_router路由包,实现用户登录状态持久化保持。
根组件中Provider注册的核心代码如下:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider( create: (ctx) => Auth(), ), ListenableProxyProvider<Auth, AppRouter>( update: (_, authObj, prevOrders) => AppRouter(authObj) ), ] // 省略剩余MaterialApp相关配置 ); } }
AppRouter类中定义了构造方法接收传入的Auth鉴权数据,初始路由配置代码如下:
class AppRouter with ChangeNotifier { final Auth authData; AppRouter(this.authData); final router = GoRouter( initialLocation: '/', routes: [ GoRoute( name: root, path: '/', builder: (context, state) => TabsScreen(), ), GoRoute( name: mainScreen, path: '/main-screen', builder: (context, state) => HomeScreen(), ), GoRoute( name: authscreen, path: '/auth-screen', builder: (context, state) => AuthScreen(), ), ], redirect: (state) { final loginLoc = state.namedLocation(authScreen); final loggingIn = state.subloc == loginLoc; var loggedIn = authData.isLoggedIn; if (!loggedIn && !loggingIn) return loginLoc; if (loggedIn && loggingIn) return root; return null; }, // 省略剩余路由配置 ); }
编译阶段抛出如下错误:
The instance member 'authData' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
报错原因
Dart类实例构造流程中,写在类成员定义位置的字段初始化器执行时机早于构造函数逻辑,此时类实例尚未完成构造,无法访问同实例下的其他成员属性。你在定义router字段时,直接在初始化表达式的redirect回调里引用authData,就会触发该编译错误。
除此之外原写法还有逻辑缺陷:Auth的登录状态变更时,GoRouter无法自动感知变化触发重定向,即使解决编译问题,登录、退出操作后路由也不会自动跳转。
修复方案
- 将
router字段改为late final延迟初始化,把GoRouter的实例化逻辑挪到构造函数中执行,该阶段authData已经完成赋值,可以正常访问。 - 在AppRouter构造函数中监听
authData的状态变化,状态变更时调用notifyListeners(),同时给GoRouter传入refreshListenable参数绑定当前AppRouter实例,鉴权状态变化时路由会自动触发redirect逻辑。 - 可选重写
dispose方法移除监听,避免内存泄漏。
修复后的AppRouter完整代码如下:
class AppRouter with ChangeNotifier { final Auth authData; late final GoRouter router; AppRouter(this.authData) { // 监听鉴权状态变化,通知路由刷新 authData.addListener(notifyListeners); // 构造函数执行阶段authData已完成初始化,可正常访问 router = GoRouter( initialLocation: '/', // 绑定刷新监听,状态变化时自动执行重定向 refreshListenable: this, routes: [ GoRoute( name: root, path: '/', builder: (context, state) => TabsScreen(), ), GoRoute( name: mainScreen, path: '/main-screen', builder: (context, state) => HomeScreen(), ), GoRoute( name: authscreen, path: '/auth-screen', builder: (context, state) => AuthScreen(), ), ], redirect: (state) { final loginLoc = state.namedLocation(authScreen); final loggingIn = state.subloc == loginLoc; final loggedIn = authData.isLoggedIn; if (!loggedIn && !loggingIn) return loginLoc; if (loggedIn && loggingIn) return state.namedLocation(root); return null; }, ); } @override void dispose() { authData.removeListener(notifyListeners); super.dispose(); } }
内容的提问来源于stack exchange,提问作者Behnam
相关产品推荐
相关产品推荐

