错误状态:使用 firstWhere 函数时没有元素
Bad State: no element when using firstWhere function
当我尝试比较从路由中获取的参数与列表的值时,我遇到了上述错误。
MealDetailScreen 小部件
import 'package:flutter/material.dart';
import '../dummy_data.dart';
class MealDetailScreen extends StatelessWidget {
static const detailScreenRouteName = '/meal-detail';
@override
Widget build(BuildContext context) {
final mealId = ModalRoute.of(context)!.settings.arguments;
final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId);
return Scaffold(
appBar: AppBar(title: Text('$mealId')),
body: Container(
child: Column(
children: [
Container(
height: 300,
width: double.infinity,
child: Image.network(
selectedMeal.imageUrl,
fit: BoxFit.cover,
),
)
],
),
),
);
}
}
如果我尝试将可选参数 'orElse' 添加到 firstWhere 函数,我仍然会收到错误消息:这次是 return 类型 'Null' 不是't a 'Meal',根据闭包上下文的要求。
这是我用来比较 id 的列表。
const DUMMY_MEALS = [
Meal(
isVegetarian: false,
isLactoseFree: false,
isVegan: false,
id: 'm1',
categories: [
'c1',
'c2',
],
title: 'Spaghetti with Tomato Sauce',
affordability: Affordability.Affordable,
complexity: Complexity.Simple,
imageUrl: '...',
duration: 20,
ingredients: ['4 Tomatoes', '...'],
steps: ['Cut the tomatoes and the onion into small pieces.', '...'],
isGlutenFree: false,
),
];
这就是我将 id 作为参数传递的方式
void selectMeal(BuildContext context) {
Navigator.of(context)
.pushNamed(MealDetailScreen.detailScreenRouteName, arguments: {id});
}
餐模
import 'package:flutter/foundation.dart';
enum Complexity { Simple, Challenging, Hard }
enum Affordability { Affordable, Pricey, Luxurious }
class Meal {
final String id;
final List<String> categories;
final String title;
final String imageUrl;
final List<String> ingredients;
final List<String> steps;
final int duration;
final Complexity complexity;
final Affordability affordability;
final bool isGlutenFree;
final bool isLactoseFree;
final bool isVegan;
final bool isVegetarian;
const Meal(
{required this.id,
required this.categories,
required this.title,
required this.imageUrl,
required this.ingredients,
required this.steps,
required this.duration,
required this.complexity,
required this.affordability,
required this.isGlutenFree,
required this.isLactoseFree,
required this.isVegan,
required this.isVegetarian});
}
在超过 arguments: {id}
时,你正在超过 _HashSet<String>
。但是对于单个值 id
string 就足够了,否则使用 map.
在这种情况下传递参数将是
Navigator.of(context)
.pushNamed(MealDetailScreen.detailScreenRouteName, arguments: id);
在迭代 DUMMY_MEALS
列表时,我们可能会得到 DUMMY_MEALS
列表中未包含的 id
。在这种情况下,您可以在 orElse
状态下创建并传递 emptyMeal 或仅使用 try catch
来处理异常。
Meal? selectedMeal;
try {
final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId);
} catch (e) {
print(e.toString());
}
虽然 selectedMeal
可以为空,但我们可以检查它是否包含膳食。
return Scaffold(
appBar: AppBar(title: Text('$mealId')),
body: selectedMeal == null
? Text("Cound not find data")
: Container(
child: Column(
children: [
Text(selectedMeal.title),
],
),
),
);
答案已经给出。但我想提一下,如果您使用的是 pushNamed 方法,建议您使用 onGenerateRoute 管理传递参数。所以你不需要 nullcheck 参数或上下文。
ModalRoute.of(context)?.settings?.arguments?
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == PassArgumentsScreen.routeName) {
final args = settings.arguments as ScreenArguments;
return MaterialPageRoute(
builder: (context) {
return PassArgumentsScreen(
title: args.title,
message: args.message,
);
},
);
}
assert(false, 'Need to implement ${settings.name}');
return null;
},
)
当我尝试比较从路由中获取的参数与列表的值时,我遇到了上述错误。
MealDetailScreen 小部件
import 'package:flutter/material.dart';
import '../dummy_data.dart';
class MealDetailScreen extends StatelessWidget {
static const detailScreenRouteName = '/meal-detail';
@override
Widget build(BuildContext context) {
final mealId = ModalRoute.of(context)!.settings.arguments;
final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId);
return Scaffold(
appBar: AppBar(title: Text('$mealId')),
body: Container(
child: Column(
children: [
Container(
height: 300,
width: double.infinity,
child: Image.network(
selectedMeal.imageUrl,
fit: BoxFit.cover,
),
)
],
),
),
);
}
}
如果我尝试将可选参数 'orElse' 添加到 firstWhere 函数,我仍然会收到错误消息:这次是 return 类型 'Null' 不是't a 'Meal',根据闭包上下文的要求。
这是我用来比较 id 的列表。
const DUMMY_MEALS = [
Meal(
isVegetarian: false,
isLactoseFree: false,
isVegan: false,
id: 'm1',
categories: [
'c1',
'c2',
],
title: 'Spaghetti with Tomato Sauce',
affordability: Affordability.Affordable,
complexity: Complexity.Simple,
imageUrl: '...',
duration: 20,
ingredients: ['4 Tomatoes', '...'],
steps: ['Cut the tomatoes and the onion into small pieces.', '...'],
isGlutenFree: false,
),
];
这就是我将 id 作为参数传递的方式
void selectMeal(BuildContext context) {
Navigator.of(context)
.pushNamed(MealDetailScreen.detailScreenRouteName, arguments: {id});
}
餐模
import 'package:flutter/foundation.dart';
enum Complexity { Simple, Challenging, Hard }
enum Affordability { Affordable, Pricey, Luxurious }
class Meal {
final String id;
final List<String> categories;
final String title;
final String imageUrl;
final List<String> ingredients;
final List<String> steps;
final int duration;
final Complexity complexity;
final Affordability affordability;
final bool isGlutenFree;
final bool isLactoseFree;
final bool isVegan;
final bool isVegetarian;
const Meal(
{required this.id,
required this.categories,
required this.title,
required this.imageUrl,
required this.ingredients,
required this.steps,
required this.duration,
required this.complexity,
required this.affordability,
required this.isGlutenFree,
required this.isLactoseFree,
required this.isVegan,
required this.isVegetarian});
}
在超过 arguments: {id}
时,你正在超过 _HashSet<String>
。但是对于单个值 id
string 就足够了,否则使用 map.
在这种情况下传递参数将是
Navigator.of(context)
.pushNamed(MealDetailScreen.detailScreenRouteName, arguments: id);
在迭代 DUMMY_MEALS
列表时,我们可能会得到 DUMMY_MEALS
列表中未包含的 id
。在这种情况下,您可以在 orElse
状态下创建并传递 emptyMeal 或仅使用 try catch
来处理异常。
Meal? selectedMeal;
try {
final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId);
} catch (e) {
print(e.toString());
}
虽然 selectedMeal
可以为空,但我们可以检查它是否包含膳食。
return Scaffold(
appBar: AppBar(title: Text('$mealId')),
body: selectedMeal == null
? Text("Cound not find data")
: Container(
child: Column(
children: [
Text(selectedMeal.title),
],
),
),
);
答案已经给出。但我想提一下,如果您使用的是 pushNamed 方法,建议您使用 onGenerateRoute 管理传递参数。所以你不需要 nullcheck 参数或上下文。
ModalRoute.of(context)?.settings?.arguments?
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == PassArgumentsScreen.routeName) {
final args = settings.arguments as ScreenArguments;
return MaterialPageRoute(
builder: (context) {
return PassArgumentsScreen(
title: args.title,
message: args.message,
);
},
);
}
assert(false, 'Need to implement ${settings.name}');
return null;
},
)