当前页面BLOC Provider无创建类时,如何基于BLOC模式实现POST请求?
基于Bloc模式实现登录POST请求
1. 添加依赖
先在pubspec.yaml中引入所需依赖:
dependencies: flutter: sdk: flutter flutter_bloc: ^8.1.3 http: ^1.1.0
执行flutter pub get完成依赖安装。
2. 创建Bloc核心组件
2.1 定义登录事件
创建login_event.dart文件:
part of 'login_bloc.dart'; abstract class LoginEvent extends Equatable { const LoginEvent(); @override List<Object> get props => []; } class LoginSubmitted extends LoginEvent { final String username; final String password; const LoginSubmitted({required this.username, required this.password}); @override List<Object> get props => [username, password]; }
2.2 定义登录状态
创建login_state.dart文件:
part of 'login_bloc.dart'; abstract class LoginState extends Equatable { const LoginState(); @override List<Object> get props => []; } class LoginInitial extends LoginState {} class LoginLoading extends LoginState {} class LoginSuccess extends LoginState { final String token; const LoginSuccess({required this.token}); @override List<Object> get props => [token]; } class LoginFailure extends LoginState { final String error; const LoginFailure({required this.error}); @override List<Object> get props => [error]; }
2.3 实现LoginBloc逻辑
创建login_bloc.dart文件,处理POST请求和状态流转:
import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; part 'login_event.dart'; part 'login_state.dart'; class LoginBloc extends Bloc<LoginEvent, LoginState> { final http.Client httpClient; LoginBloc({required this.httpClient}) : super(LoginInitial()) { on<LoginSubmitted>(_onLoginSubmitted); } Future<void> _onLoginSubmitted( LoginSubmitted event, Emitter<LoginState> emit, ) async { emit(LoginLoading()); try { // 替换为你的实际登录接口地址 final response = await httpClient.post( Uri.parse('https://your-api-domain.com/login'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'username': event.username, 'password': event.password, }), ); if (response.statusCode == 200) { final data = jsonDecode(response.body); emit(LoginSuccess(token: data['token'])); } else { final errorMsg = jsonDecode(response.body)['message'] ?? '登录失败,请重试'; emit(LoginFailure(error: errorMsg)); } } catch (e) { emit(LoginFailure(error: '网络连接异常,请检查网络')); } } }
3. 集成Bloc到登录页面
修改原main.dart,通过BlocProvider注入Bloc实例,并更新LoginPage的UI逻辑:
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:http/http.dart' as http; import 'login_bloc.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: false, ), home: BlocProvider( create: (context) => LoginBloc(httpClient: http.Client()), child: const LoginPage(), ), ); } } class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { TextEditingController userName = TextEditingController(); TextEditingController password = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( body: BlocConsumer<LoginBloc, LoginState>( listener: (context, state) { // 监听状态变化处理副作用 if (state is LoginSuccess) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('登录成功!Token: ${state.token}')), ); // 这里可以添加跳转到主页的逻辑 } else if (state is LoginFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.error), backgroundColor: Colors.red), ); } }, builder: (context, state) { return Container( width: MediaQuery.of(context).size.width, padding: const EdgeInsets.only(left: 20, right: 20), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("User Name"), TextField( controller: userName, enabled: state is! LoginLoading, // 加载时禁用输入框 ), const Padding( padding: EdgeInsets.only(top: 20), child: Text("Password"), ), TextField( controller: password, obscureText: true, enabled: state is! LoginLoading, ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.only(top: 20), child: ElevatedButton( onPressed: state is LoginLoading ? null // 加载时禁用按钮 : () { // 触发登录事件 context.read<LoginBloc>().add( LoginSubmitted( username: userName.text, password: password.text, ), ); }, child: state is LoginLoading ? const CircularProgressIndicator(color: Colors.white) : const Text('Login'), ), ), ], ) ], ), ); }, ), ); } }
核心逻辑说明
- 事件触发:点击登录按钮时,通过
context.read<LoginBloc>().add(...)发送登录事件 - 状态管理:Bloc内部处理POST请求,根据接口响应更新状态(加载中/成功/失败)
- UI响应:
BlocConsumer同时处理UI渲染(比如加载时显示进度条、禁用交互)和状态变化的副作用(提示消息、页面跳转)
内容的提问来源于stack exchange,提问作者Rajasekaran K
相关产品推荐
相关产品推荐

