Please help! I'm using riverpod with the redo and undo buttons in my app, but keep getting "This expression has a type of 'void' so its value can't be used. Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void" I exhausted all my options. Find my code below(Ln 58 -71):
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final drawingAreaProvider =
StateNotifierProvider.autoDispose<DrawingAreaNotifier, List<Offset>>((ref) {
return DrawingAreaNotifier();
});
final redoProvider = StateProvider.autoDispose<void>((ref) {});
final undoProvider = StateProvider.autoDispose<void>((ref) {});
final toggleGridProvider = StateProvider.autoDispose<bool>((ref) => false);
class DrawingAreaNotifier extends StateNotifier<List<Offset>> {
DrawingAreaNotifier() : super([]);
void addPoint(Offset point) {
state = [...state, point];
}
void clearPoints() {
state = [];
}
}
class DrawingArea extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final points = ref.watch(drawingAreaProvider);
return GestureDetector(
onPanStart: (details) {
final RenderBox renderBox = context.findRenderObject() as RenderBox;
final localPosition = renderBox.globalToLocal(details.globalPosition);
ref.read(drawingAreaProvider.notifier).addPoint(localPosition);
},
onPanUpdate: (details) {
final RenderBox renderBox = context.findRenderObject() as RenderBox;
final localPosition = renderBox.globalToLocal(details.globalPosition);
ref.read(drawingAreaProvider.notifier).addPoint(localPosition);
},
onPanEnd: (_) {
// Do nothing on pan end
},
child: Stack(
children: [
CustomPaint(
painter: DrawingPainter(points),
size: Size.infinite,
),
Positioned(
top: 20,
left: 20,
child: Row(
children: [
IconButton(
icon: const Icon(Icons.undo),
onPressed: () {
ref.read(undoProvider).state;
},
),
IconButton(
icon: Icon(Icons.redo),
onPressed: () {
ref.read(redoProvider).state;
},
),
IconButton(
icon: Icon(Icons.grid_on),
onPressed: () {
ref.read(toggleGridProvider).state =
!ref.read(toggleGridProvider).state;
},
),
],
),
),
],
),
);
}
}
class DrawingPainter extends CustomPainter {
final List<Offset> points;
DrawingPainter(this.points);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.black
..strokeWidth = 2
..style = PaintingStyle.stroke;
if (points.isEmpty) return;
final path = Path();
path.moveTo(points.first.dx, points.first.dy);
for (int i = 1; i < points.length; i++) {
path.lineTo(points[i].dx, points[i].dy);
}
canvas.drawPath(path, paint);
final crossPaint = Paint()
..color = Colors.red
..strokeWidth = 2;
for (final point in points) {
canvas.drawLine(Offset(point.dx - 5, point.dy),
Offset(point.dx + 5, point.dy), crossPaint);
canvas.drawLine(Offset(point.dx, point.dy - 5),
Offset(point.dx, point.dy + 5), crossPaint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
I tried to update these providers to use the correct syntax for initializing the state.
final redoProvider = StateProvider.autoDispose<void>((ref) => null);
final undoProvider = StateProvider.autoDispose<void>((ref) => null);
final toggleGridProvider = StateProvider.autoDispose<bool>((ref) => false);
Still didn't help
It is expected that your code throws an error. As indicated in the "state" property of StateNotifier it is
@protectedand@visibleForTesting, which implies that it can only be accessed from child classes and test.As recommended by the Riverpod documentation, if you want to reactively get a provided value, i.e. rebuild you widgets on changes of the provider, you shall use "watch" instead of "read".
On the other hand, if you want to get the provided value "on-demand", for example within a callback function of a button, then you shall use "read".
Note that both "watch" and "read" can only be used to get the value/state provided by the provider.