使用Flutter Riverpod实现页面传参及单篇文章数据获取的问题
解决Flutter Riverpod路由传参及API请求参数传递问题
问题背景
使用Flutter结合flutter_riverpod开发应用,习惯了GetX的路由传参方式,对Riverpod不熟悉。现有三个核心文件:
- AAmain.dart:首页,通过HTTP请求获取文章列表并展示
- AAx2.dart:文章详情页,展示单篇文章的图片、标题等内容
- AAapi.dart:仅包含获取单篇文章数据的HTTP请求函数
fetch_1WpPosts
核心问题:点击首页文章项跳转详情页时,无法将文章slug参数传递给AAapi.dart——该文件没有ProviderScope、ref或WidgetRef,导致fetch_1WpPosts无法获取状态拼接请求URL。
解决方案
1. 重构AAapi.dart:让API函数直接接收参数
移除对Riverpod ref的依赖,将slug作为参数传入API函数,这是最直接的方式,避免不必要的状态依赖:
import 'package:http/http.dart' as http; import 'dart:convert'; Future<List<dynamic>> fetch_1WpPosts(String slug) async { final baseUrl = 'https://meshcurrent.online/wp/wp-json/api/v1/posts/'; final requestUrl = '$baseUrl$slug'; final response = await http.get(Uri.parse(requestUrl)); List<dynamic> convertDataJson = jsonDecode(response.body); return convertDataJson; }
2. 修改AAmain.dart:跳转时传递slug参数
删除无效的StateProvider定义,通过路由直接传递slug参数到AAx2页面:
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'wp-api.dart'; import 'AAx2.dart'; import 'package:flutter_eem_1/custom.dart'; void main() { runApp(const ProviderScope(child: benimApp0())); } class benimApp0 extends ConsumerWidget { const benimApp0({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return MaterialApp( theme: ThemeData(), home: const Scaffold( body: SafeArea( child: xMyHomePage(), ), ), ); } } class xMyHomePage extends ConsumerWidget { const xMyHomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( body: Column( children: [ Expanded( child: FutureBuilder<List<dynamic>>( future: fetchWpPosts(), builder: (context, snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: 5, itemBuilder: (BuildContext context, int index) { final postSlug = snapshot.data![index]["slug"]; return InkWell( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => x2(postSlug: postSlug), ), ); }, child: Column( children: [ Image.network( snapshot.data![index]["featured_image"]["large"].toString(), ), ], ), ); }, ); } return const Center(child: CircularProgressIndicator()); }, ), ), ], ), ); } }
3. 修改AAx2.dart:接收路由参数并传递给API
修改x2组件,添加接收slug的构造函数,在FutureBuilder中传递参数给fetch_1WpPosts:
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_eem_1/AAapi.dart'; class x2 extends ConsumerWidget { final String postSlug; const x2({super.key, required this.postSlug}); @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( body: SafeArea( child: SingleChildScrollView( child: FutureBuilder<List<dynamic>>( future: fetch_1WpPosts(postSlug), builder: (context, snapshot) { if (snapshot.hasData) { final post = snapshot.data![0]; return Column( children: [ Text( post["title"], style: const TextStyle( fontSize: 25, fontWeight: FontWeight.bold, ), ), Image.network(post["featured_image_large"]), ], ); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } return const Center(child: CircularProgressIndicator()); }, ), ), ), ); } }
(可选)用Riverpod FutureProvider封装API请求(最佳实践)
如果想利用Riverpod的状态管理能力自动处理加载、错误状态,可以将API请求封装为FutureProvider:
第一步:在AAapi.dart中定义Provider
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; final singlePostProvider = FutureProvider.family<List<dynamic>, String>((ref, slug) async { final baseUrl = 'https://meshcurrent.online/wp/wp-json/api/v1/posts/'; final requestUrl = '$baseUrl$slug'; final response = await http.get(Uri.parse(requestUrl)); return jsonDecode(response.body); });
第二步:修改AAx2.dart使用Provider
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_eem_1/AAapi.dart'; class x2 extends ConsumerWidget { final String postSlug; const x2({super.key, required this.postSlug}); @override Widget build(BuildContext context, WidgetRef ref) { final postAsyncValue = ref.watch(singlePostProvider(postSlug)); return Scaffold( body: SafeArea( child: postAsyncValue.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => Center(child: Text('加载失败: $error')), data: (postData) { final post = postData[0]; return SingleChildScrollView( child: Column( children: [ Text( post["title"], style: const TextStyle( fontSize: 25, fontWeight: FontWeight.bold, ), ), Image.network(post["featured_image_large"]), ], ), ); }, ), ), ); } }
内容的提问来源于stack exchange,提问作者mesh
相关产品推荐
相关产品推荐

