Flutter路由与状态管理插件riverpod_consumer_router_delegate的使用

Flutter路由与状态管理插件riverpod_consumer_router_delegate的使用

riverpod_consumer_router_delegate

特性

这个包让你能够将 flutter_riverpod 包与 flutter navigator 2.0 API 结合起来使用。

在自定义的路由器委托类中,你可以像在小部件中一样使用 <code>ref.watch()</code><code>ref.read()</code><code>ref.listen()</code><code>ref.refresh()</code> 方法。


使用方法

以下是使用 riverpod_consumer_router_delegate 的完整步骤和代码示例:

1. 扩展你的 RouterDelegate 类为 ConsumerRouterDelegate

class MyRouterDelegate extends ConsumerRouterDelegate<MyRouteConfig>
    with PopNavigatorRouterDelegateMixin<MyRouteConfig>, ChangeNotifier {
  // 确保将 `ref` 传递给 `super` 构造函数
  MyRouterDelegate(Ref ref) : super(ref);

  // ...
}

2. 实现 <code>onDependenciesUpdate()</code> 方法

如果你的路由器委托是一个 <code>ChangeNotifier</code>,那么可以调用 <code>notifyListeners()</code> 方法:

[@override](/user/override)
void onDependenciesUpdate() {
  notifyListeners();
}

3. 在自定义路由器委托类中,不要覆盖 <code>build</code> 方法,而是编写一个 <code>builder</code> 方法

Widget builder(BuildContext context) {
  // 在这里编写你的路由构建逻辑
}

注意:<code>ref</code> 不是你传递给 <code>super</code> 构造函数的那个 ref

4. 添加一个 <code>ChangeNotifierProvider</code> 来管理你的路由器委托实例

final routerDelegateProvider = ChangeNotifierProvider((ref) => MyRouterDelegate(ref));

5. 在 <code>MaterialApp</code> 周围包裹一个 <code>ProviderScope</code>,并将路由器委托实例传递给 <code>MaterialApp.router</code> 的构造函数

void main() {
  runApp(
    const ProviderScope(child: MyApp()),
  );
}

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp.router(
      routerDelegate: ref.watch(routerDelegateProvider), // 使用 provider 提供的路由器委托
      routeInformationParser: ColorRouteInformationParser(), // 路由信息解析器
    );
  }
}

动机

Flutter 的导航器 2.0 API 采用了声明式的方法,但直接与 <code>riverpod</code> 配合使用存在一些问题。

正如在 此问题 中讨论的那样,在路由器委托的 <code>build</code> 方法中直接使用 <code>riverpod</code> 的方法(例如 <code>ref.watch()</code>)会导致一些问题。

社区建议在路由器委托的构造函数中添加所有依赖提供者的监听器,但这不是一个好主意,因为它既丑陋又容易出错。

因此,我创建了这个包。只需扩展你的路由器委托类,并将 <code>ref</code> 传递给父类构造函数,然后编写一个 <code>builder</code> 方法而不是 <code>build</code> 方法即可。它会在幕后完成魔法,让你可以像在小部件中一样使用 <code>ref.*</code> 方法,无需任何担忧。


其他信息

欢迎提交问题和拉取请求。


完整示例代码

以下是从示例文件中提取的完整代码:

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'router/route_information_parser.dart';
import 'service_locator.dart';

void main() {
  runApp(
    const ProviderScope(child: MyApp()),
  );
}

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp.router(
      routeInformationParser: ColorRouteInformationParser(),
      routerDelegate: ref.watch(routerDelegateProvider),
    );
  }
}
1 回复

更多关于Flutter路由与状态管理插件riverpod_consumer_router_delegate的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,路由管理和状态管理是两个非常重要的概念。riverpod_consumer_router_delegate 是一个结合了 Riverpod 状态管理和 Router 路由管理的插件,它允许你在使用 Riverpod 进行状态管理的同时,通过 Router 来管理应用的路由。

1. 安装依赖

首先,你需要在 pubspec.yaml 文件中添加 riverpodriverpod_consumer_router_delegate 的依赖:

dependencies:
  flutter:
    sdk: flutter
  riverpod: ^2.0.0
  riverpod_consumer_router_delegate: ^0.1.0

然后运行 flutter pub get 来安装依赖。

2. 基本使用

2.1 创建 RouterDelegate

RouterDelegateRouter 的核心部分,它负责处理路由的导航逻辑。riverpod_consumer_router_delegate 提供了一个 ConsumerRouterDelegate,它允许你在路由管理中使用 Riverpod 的状态。

import 'package:flutter/material.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_consumer_router_delegate/riverpod_consumer_router_delegate.dart';

final routerDelegateProvider = Provider<ConsumerRouterDelegate>((ref) {
  return ConsumerRouterDelegate(
    routeInformationParser: MyRouteInformationParser(),
    builder: (context, route) {
      switch (route) {
        case '/':
          return HomeScreen();
        case '/details':
          return DetailsScreen();
        default:
          return NotFoundScreen();
      }
    },
  );
});

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: MyRouteInformationParser(),
      routerDelegate: context.read(routerDelegateProvider),
    );
  }
}

2.2 创建 RouteInformationParser

RouteInformationParser 负责将 RouteInformation 转换为应用内部的路由状态。

class MyRouteInformationParser extends RouteInformationParser<String> {
  [@override](/user/override)
  Future<String> parseRouteInformation(RouteInformation routeInformation) async {
    return routeInformation.location ?? '/';
  }

  [@override](/user/override)
  RouteInformation restoreRouteInformation(String configuration) {
    return RouteInformation(location: configuration);
  }
}

2.3 使用 ConsumerRouterDelegate 进行导航

你可以在任何地方使用 ConsumerRouterDelegate 来进行导航。例如,在 HomeScreen 中导航到 DetailsScreen

class HomeScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.read(routerDelegateProvider).push('/details');
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

2.4 处理路由参数

你可以通过 ConsumerRouterDelegate 传递路由参数:

context.read(routerDelegateProvider).push('/details', arguments: {'id': 123});

DetailsScreen 中获取参数:

class DetailsScreen extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    final arguments = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
    final id = arguments?['id'];

    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(
        child: Text('Details for item $id'),
      ),
    );
  }
}

3. 结合 Riverpod 进行状态管理

ConsumerRouterDelegate 允许你在路由管理中使用 Riverpod 的状态。例如,你可以在 ConsumerRouterDelegatebuilder 中使用 Consumer 来获取状态:

final counterProvider = StateProvider<int>((ref) => 0);

class HomeScreen extends ConsumerWidget {
  [@override](/user/override)
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Counter: $counter'),
            ElevatedButton(
              onPressed: () {
                ref.read(counterProvider.notifier).state++;
              },
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!