显示一个对话框,而不是使用Flutter/Dat中的任一返回小部件



我有点卡住了,不知道架构流在这个用例中应该如何工作。我对函数式编程几乎一无所知,我使用的是来自dartz包的函数式编程包。有人能帮我做以下事情吗:

如果出现错误,我想显示一个弹出对话框而不是小部件。但是,如果逻辑当然需要一个小部件,那么"非此即彼"的设计似乎不允许这样做。有没有更好的设计可以让我做到这一点?

此处学习错误处理

import 'dart:convert';
import 'dart:io';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ProviderScope(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: const HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueGrey,
body: Flex(
direction: Axis.horizontal,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Consumer(
builder: (ctx, ref, child) {
if (ref.watch(notifier).state == NotifierState.initial) {
return const Text('Press the button');
} else if (ref.watch(notifier).state == NotifierState.loading) {
return const CircularProgressIndicator();
} else {
return ref.read(notifier).post.fold(
(failure) {
showDialog(                     /// Error here, expects a widget
context: context,
barrierDismissible: true,
builder: (BuildContext context) => AlertDialog(
title: Text(failure.toString()),
),
);
},
(post) => Text(post.toString()),
);
}
},
),
Consumer(
builder: (ctx, ref, child) {
return ElevatedButton(
onPressed: () {
ref.read(notifier).getOnePost();
},
child: const Text('Get Post'));
},
),
],
),
),
],
),
);
}
}
class PostService {
final httpClient = FakeHttpClient();
Future<Post?> getOnePost() async {
try {
final responseBody = await httpClient.getResponseBody();
return Post.fromJson(responseBody);
} on SocketException {
throw Failure('No Internet connection 😑');
} on HttpException {
throw Failure("Couldn't find the post 😱");
} on FormatException {
throw Failure("Bad response format 👎");
}
}
}
class FakeHttpClient {
Future<String> getResponseBody() async {
await Future.delayed(const Duration(milliseconds: 500));
//! No Internet Connection
// throw SocketException('No Internet');
//! 404
throw HttpException('404');
//! Invalid JSON (throws FormatException)
// return 'abcd';
// return '{"userId":1,"id":1,"title":"nice title","body":"cool body"}';
}
}
enum NotifierState { initial, loading, loaded }
final notifier = ChangeNotifierProvider((ref) => PostChangeNotifier());
class PostChangeNotifier extends ChangeNotifier {
final _postService = PostService();
NotifierState _state = NotifierState.initial;
NotifierState get state => _state;
void _setState(NotifierState state) {
_state = state;
notifyListeners();
}
late Either<Failure, Post?> _post;
Either<Failure, Post?> get post => _post;
// Set post
void _setPost(Either<Failure, Post?> post) {
_post = post;
notifyListeners();
}
// Set one post
void getOnePost() async {
_setState(NotifierState.loading);
await Task(() => _postService.getOnePost())
.attempt()
.mapLeftToFailure()
.run()
.then((value) => _setPost(value as Either<Failure, Post?>));
_setState(NotifierState.loaded);
}
}
extension TaskX<T extends Either<Object, U>, U> on Task<T> {
Task<Either<Failure, U>> mapLeftToFailure() {
return map(
(either) => either.leftMap((obj) {
try {
return obj as Failure;
} catch (e) {
throw obj;
}
}),
);
}
}
class Post {
final int id;
final int userId;
final String title;
final String body;
Post({
required this.id,
required this.userId,
required this.title,
required this.body,
});
static Post? fromMap(Map<String, dynamic> map) {
return Post(
id: map['id'],
userId: map['userId'],
title: map['title'],
body: map['body'],
);
}
static Post? fromJson(String source) => fromMap(json.decode(source));
@override
String toString() {
return 'Post id: $id, userId: $userId, title: $title, body: $body';
}
}
class Failure {
// Use something like "int code;" if you want to translate error messages
final String message;
Failure(this.message);
@override
String toString() => message;
}

您不需要调用函数而不是小部件,您应该调用类并在initState中初始化您的对话框

// call show dialog
(failure) {
ShowDialogScreen(failure: failure.toString());
},
// show dialog screen 
class ShowDialogScreen extends StatefulWidget {
final String failure;
const ShowDialogScreen({Key key, this.failure}) : super(key: key);
@override
_ShowDialogScreenState createState() => _ShowDialogScreenState();
}
class _ShowDialogScreenState extends State<ShowDialogScreen> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) => AlertDialog(
title: Text(widget.failure),
),
);
});
}
@override
Widget build(BuildContext context) {
return Container();
}
}

最新更新