Riverpod调用add/editExercise报位置参数过多错误的解决方法
Riverpod调用方法提示参数过多的解决办法
错误信息
59:27: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
context.read(exerciseControllerProvider).addExercise(newExercise);
62:27: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
context.read(exerciseControllerProvider).editExercise(updatedExercise);
问题代码
ExerciseScreen 代码
import 'package:flutter/material.dart'; import 'package:song/core/models/exercise.dart'; import 'package:song/widgets/exercise_form.dart'; import 'package:song/core/models/exercise_types/front_back.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:song/core/providers/exercise_provider.dart'; import 'package:song/widgets/type_forms/type_controllers.dart'; class ExerciseScreen extends StatefulWidget { final Exercise? exercise; ExerciseScreen({Key? key, this.exercise}) : super(key: key); @override _ExerciseScreenState createState() => _ExerciseScreenState(); } class _ExerciseScreenState extends State<ExerciseScreen> { GlobalKey<FormState> _formKey = GlobalKey<FormState>(); TypeControllers? _controllers; @override void initState() { super.initState(); _controllers = TypeControllers( questionController: TextEditingController(text: widget.exercise?.question ?? ''), answerController: TextEditingController(text: widget.exercise?.answer ?? ''), ); } @override void dispose() { _controllers?.questionController.dispose(); _controllers?.answerController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.exercise == null ? 'Create Exercise' : 'Edit Exercise'), ), body: Padding( padding: EdgeInsets.all(16), child: ExerciseForm( exercise: widget.exercise ?? FrontBack(id: '', front: '', back: ''), formKey: _formKey, controllers: _controllers!, ), ), floatingActionButton: FloatingActionButton( onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); if (widget.exercise == null) { Exercise newExercise = FrontBack(id: '', front: _controllers!.questionController.text, back: _controllers!.answerController.text); context.read(exerciseControllerProvider).addExercise(newExercise); } else { Exercise updatedExercise = (widget.exercise as FrontBack).copyWith(front: _controllers!.questionController.text, back: _controllers!.answerController.text); context.read(exerciseControllerProvider).editExercise(updatedExercise); } Navigator.pop(context); } }, child: Icon(Icons.check), ), ); } }
Provider 代码
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:song/core/models/exercise.dart'; import 'package:state_notifier/state_notifier.dart'; class ExerciseController extends StateNotifier<List<Exercise>> { ExerciseController() : super([]); void addExercise(Exercise exercise) { state = [...state, exercise]; } void editExercise(Exercise updatedExercise) { state = state.map((exercise) => exercise.id == updatedExercise.id ? updatedExercise : exercise).toList(); } void removeExercise(String id) { state = state.where((exercise) => exercise.id != id).toList(); } } final exerciseControllerProvider = StateNotifierProvider<ExerciseController, List<Exercise>>( (ref) => ExerciseController(), );
TypeControllers 代码
import 'package:flutter/material.dart'; class TypeControllers { TextEditingController questionController; TextEditingController answerController; TypeControllers({required this.questionController, required this.answerController}); }
问题原因
这是Riverpod版本差异导致的API调用变化:
- Riverpod 1.x中,
context.read(provider)直接返回StateNotifier实例,可直接调用addExercise方法。 - 但Riverpod 2.x中,
context.read(provider)返回的是状态值(此处为List<Exercise>),而列表没有addExercise方法,因此会提示参数错误。
解决方案
方法1:快速修复 - 调用notifier属性获取控制器
直接修改调用代码,通过notifier属性拿到StateNotifier实例:
// 新增练习的代码改成: context.read(exerciseControllerProvider.notifier).addExercise(newExercise); // 编辑练习的代码改成: context.read(exerciseControllerProvider.notifier).editExercise(updatedExercise);
方法2:推荐写法 - 使用ConsumerStatefulWidget
把原来的StatefulWidget改成ConsumerStatefulWidget,通过ref获取控制器,这是Riverpod 2.x的最佳实践:
修改后的ExerciseScreen代码:
import 'package:flutter/material.dart'; import 'package:song/core/models/exercise.dart'; import 'package:song/widgets/exercise_form.dart'; import 'package:song/core/models/exercise_types/front_back.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:song/core/providers/exercise_provider.dart'; import 'package:song/widgets/type_forms/type_controllers.dart'; class ExerciseScreen extends ConsumerStatefulWidget { final Exercise? exercise; ExerciseScreen({Key? key, this.exercise}) : super(key: key); @override _ExerciseScreenState createState() => _ExerciseScreenState(); } class _ExerciseScreenState extends ConsumerState<ExerciseScreen> { GlobalKey<FormState> _formKey = GlobalKey<FormState>(); TypeControllers? _controllers; @override void initState() { super.initState(); _controllers = TypeControllers( questionController: TextEditingController(text: widget.exercise?.question ?? ''), answerController: TextEditingController(text: widget.exercise?.answer ?? ''), ); } @override void dispose() { _controllers?.questionController.dispose(); _controllers?.answerController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.exercise == null ? 'Create Exercise' : 'Edit Exercise'), ), body: Padding( padding: EdgeInsets.all(16), child: ExerciseForm( exercise: widget.exercise ?? FrontBack(id: '', front: '', back: ''), formKey: _formKey, controllers: _controllers!, ), ), floatingActionButton: FloatingActionButton( onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); // 通过ref获取控制器实例 final exerciseController = ref.read(exerciseControllerProvider.notifier); if (widget.exercise == null) { Exercise newExercise = FrontBack(id: '', front: _controllers!.questionController.text, back: _controllers!.answerController.text); exerciseController.addExercise(newExercise); } else { Exercise updatedExercise = (widget.exercise as FrontBack).copyWith(front: _controllers!.questionController.text, back: _controllers!.answerController.text); exerciseController.editExercise(updatedExercise); } Navigator.pop(context); } }, child: Icon(Icons.check), ), ); } }
两种方法都能解决问题,方法2更符合Riverpod 2.x的设计理念,后续维护也更方便。
内容的提问来源于stack exchange,提问作者Coding_noob
相关产品推荐
相关产品推荐

