告别重复网络代码:Flutter Hooks+Dio自定义Hook封装指南

告别重复网络代码:Flutter Hooks+Dio自定义Hook封装指南

【免费下载链接】dio A powerful HTTP client for Dart and Flutter, which supports global settings, Interceptors, FormData, aborting and canceling a request, files uploading and downloading, requests timeout, custom adapters, etc. 【免费下载链接】dio 项目地址: https://gitcode.com/gh_mirrors/di/dio

你是否还在为Flutter项目中重复的网络请求代码感到困扰?每次发起请求都要处理加载状态、错误捕获和数据解析,不仅冗余还容易出错。本文将带你通过Flutter Hooks与Dio的结合,打造一个优雅的网络请求解决方案,让你的代码更简洁、更可维护。读完本文,你将掌握自定义Hook封装Dio的完整流程,学会如何在实际项目中应用这一最佳实践。

技术选型:为什么选择Dio和Flutter Hooks?

Dio作为Flutter生态中最强大的HTTP客户端,提供了拦截器、FormData、文件上传下载等丰富功能,其核心代码位于dio/lib/dio.dart。而Flutter Hooks则是一个轻量级的状态管理库,通过自定义Hook可以将组件逻辑抽象复用,两者结合能极大提升开发效率。

核心优势对比

传统方式Hooks封装方式
重复State声明单一Hook调用
生命周期复杂useEffect统一管理
错误处理分散集中式异常捕获
代码冗余度高逻辑抽象复用

从零开始:自定义Hook封装步骤

1. 基础架构搭建

首先创建一个网络请求基础类,封装Dio实例和拦截器配置:

// [example_flutter_app/lib/http.dart](https://link.gitcode.com/i/f2bec7539b5a6d2bf4e0bb384e1dc824)
import 'package:dio/dio.dart';

class HttpUtil {
  static final Dio _dio = Dio(BaseOptions(
    baseUrl: 'https://api.example.com',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 3),
  ));

  static Dio get instance => _dio;

  static void init() {
    _dio.interceptors.add(LogInterceptor(responseBody: true));
    // 可添加CookieManager等插件 [plugins/cookie_manager/](https://link.gitcode.com/i/dbd751c8825bf535b01dbb2ad8edd8ca)
  }
}

2. 网络请求Hook实现

创建useRequest自定义Hook,统一管理请求状态:

// [example_flutter_app/lib/routes/request.dart](https://link.gitcode.com/i/c70141830aae454eba8a55cbc10d8f4a)
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:dio/dio.dart';

typedef RequestCallback<T> = Future<T> Function();

class RequestResult<T> {
  final T? data;
  final bool loading;
  final DioException? error;

  RequestResult({this.data, required this.loading, this.error});
}

RequestResult<T> useRequest<T>(RequestCallback<T> request) {
  final data = useState<T?>(null);
  final loading = useState<bool>(false);
  final error = useState<DioException?>(null);
  final cancelToken = CancelToken();

  useEffect(() {
    return () => cancelToken.cancel('Request canceled');
  }, []);

  Future<void> execute() async {
    loading.value = true;
    try {
      final result = await request();
      data.value = result;
      error.value = null;
    } on DioException catch (e) {
      error.value = e;
    } finally {
      loading.value = false;
    }
  }

  return RequestResult(
    data: data.value,
    loading: loading.value,
    error: error.value,
  );
}

3. 高级功能集成

添加请求取消和进度监听功能,利用Dio的CancelToken和Stream:

// 添加文件上传进度监听
void uploadFile(String path) async {
  await HttpUtil.instance.post(
    '/upload',
    data: FormData.fromMap({
      'file': await MultipartFile.fromFile(path),
    }),
    onSendProgress: (int sent, int total) {
      double progress = sent / total;
      print('上传进度: ${(progress * 100).toStringAsFixed(0)}%');
    },
  );
}

实际应用:用户登录场景示例

// [example_flutter_app/lib/main.dart](https://link.gitcode.com/i/c34ea1e750390b00d2c96642ab0ad7c3)
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:dio/dio.dart';
import 'http.dart';
import 'routes/request.dart';

class LoginPage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final username = useState('');
    final password = useState('');
    
    final request = useRequest(() async {
      return await HttpUtil.instance.post(
        '/login',
        data: {'username': username.value, 'password': password.value},
      );
    });

    return Scaffold(
      body: Column(
        children: [
          TextField(
            onChanged: (v) => username.value = v,
            decoration: InputDecoration(labelText: '用户名'),
          ),
          TextField(
            onChanged: (v) => password.value = v,
            obscureText: true,
            decoration: InputDecoration(labelText: '密码'),
          ),
          ElevatedButton(
            onPressed: request.loading ? null : () => request.execute(),
            child: request.loading ? CircularProgressIndicator() : Text('登录'),
          ),
          if (request.error != null) 
            Text('登录失败: ${request.error!.message}', 
                style: TextStyle(color: Colors.red)),
        ],
      ),
    );
  }
}

最佳实践与避坑指南

1. 拦截器最佳配置

推荐使用拦截器处理通用逻辑,如Token刷新:

// [dio/lib/src/interceptor.dart](https://link.gitcode.com/i/8f0c447e9076460dbab843e4e56403a2)
class TokenInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.headers['Authorization'] = 'Bearer token';
    super.onRequest(options, handler);
  }

  @override
  Future onError(DioException err, ErrorInterceptorHandler handler) async {
    if (err.response?.statusCode == 401) {
      // 实现Token刷新逻辑
    }
    super.onError(err, handler);
  }
}

2. 内存管理注意事项

  • 使用CancelToken及时取消无用请求,避免内存泄漏
  • 通过useEffect清理函数释放资源
  • 避免在Hook中直接创建Dio实例,推荐使用单例模式

项目资源与扩展学习

通过Flutter Hooks与Dio的结合,我们成功将网络请求逻辑抽象为可复用的自定义Hook,大幅减少了重复代码。这种模式不仅适用于网络请求,还可推广到数据库操作、权限检查等场景。立即尝试在你的项目中应用这一实践,提升代码质量和开发效率!

如果觉得本文对你有帮助,别忘了点赞、收藏、关注三连,下期我们将探讨Dio的高级拦截器设计模式!

【免费下载链接】dio A powerful HTTP client for Dart and Flutter, which supports global settings, Interceptors, FormData, aborting and canceling a request, files uploading and downloading, requests timeout, custom adapters, etc. 【免费下载链接】dio 项目地址: https://gitcode.com/gh_mirrors/di/dio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值