BlocBuilder 未在单击浮动操作按钮时重建

问题描述 投票:0回答:1

使用 Bloc 模式显示从 REST API 获取的数据列表。 现在我想在单击按钮时更新列表视图上的列表。 当我单击按钮时,它会获取数据但不会更新列表视图 这是完整的代码。

main.dart

import 'package:bloc_demo/homepage.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
       
        primarySwatch: Colors.blue,
      ),
      home:  HomePage(),
    );
  }
}

HomePage.dart

class HomePage extends StatelessWidget {
  String pageNo = "1";
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<UserBloc>(
          create: (BuildContext context) => UserBloc(UserRepository(),pageNo),
        ),
      ],
      child: Scaffold(
        appBar: AppBar(title: const Text('The BloC App')),
        body: blocBody(),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            pageNo = "2";
            UserBloc(
              UserRepository(),pageNo,
            ).add(LoadUserEvent());
          },
          child: const Icon(Icons.navigation),
        ),
      ),
    );
  }

  Widget blocBody() {
    return BlocProvider(
      create: (context) => UserBloc(
        UserRepository(),pageNo,
      )..add(LoadUserEvent()),
      child: BlocBuilder<UserBloc, UserState>(
        builder: (context, state) {
          if (state is UserLoadingState) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
          if (state is UserLoadedState) {
            List<UserModel> userList = state.users;
            return ListView.builder(
                itemCount: userList.length,
                itemBuilder: (_, index) {
                  return Padding(
                    padding:
                        const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
                    child: Card(
                        color: Theme.of(context).primaryColor,
                        child: ListTile(
                            title: Text(
                              '${userList[index].firstName}  ${userList[index].lastName}',
                              style: const TextStyle(color: Colors.white),
                            ),
                            subtitle: Text(
                              '${userList[index].email}',
                              style: const TextStyle(color: Colors.white),
                            ),
                            leading: CircleAvatar(
                              backgroundImage: NetworkImage(
                                  userList[index].avatar.toString()),
                            ))),
                  );
                });
          }
          if (state is UserErrorState) {
            return const Center(
              child: Text("Error"),
            );
          }

          return Container();
        },
      ),
    );
  }
}

用户区块

class UserBloc extends Bloc<UserEvent, UserState> {
  final UserRepository _userRepository;
  final String pageNo;
  UserBloc(this._userRepository,this.pageNo) : super(UserLoadingState()) {
    on<LoadUserEvent>((event, emit) async {
      emit(UserLoadingState());
      try {
        final users = await _userRepository.getUsers(pageNo);
        emit(UserLoadedState(users));
      } catch (e) {
        emit(UserErrorState(e.toString()));
      }
    });
  }
}

用户事件

@immutable
abstract class UserEvent extends Equatable {
  const UserEvent();
}

class LoadUserEvent extends UserEvent {
  @override
  List<Object?> get props => [];
}

用户状态

@immutable
abstract class UserState extends Equatable {}

//data loading state
class UserLoadingState extends UserState {
  @override
  List<Object?> get props => [];
}

class UserLoadedState extends UserState {
  final List<UserModel> users;
  UserLoadedState(this.users);
  @override
  List<Object?> get props => [users];
}
class UserErrorState extends UserState {
  final String error;
  UserErrorState(this.error);
  @override
  List<Object?> get props => [error];
}

用户模型

class UserModel {
  int? id;
  String? email;
  String? firstName;
  String? lastName;
  String? avatar;

  UserModel({this.id, this.email, this.firstName, this.lastName, this.avatar});

  UserModel.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    email = json['email'];
    firstName = json['first_name'];
    lastName = json['last_name'];
    avatar = json['avatar'];
  }
}

用户存储库

class UserRepository {
  String userUrl = 'https://reqres.in/api/users?page=';

  Future<List<UserModel>> getUsers(String pageNo) async {
    Response response = await get(Uri.parse(userUrl+pageNo));

    if (response.statusCode == 200) {
      final List result = jsonDecode(response.body)['data'];
      return result.map((e) => UserModel.fromJson(e)).toList();
    } else {
      throw Exception(response.reasonPhrase);
    }
  }
}
android flutter setstate bloc do-not-use-typo-in-tag
1个回答
0
投票

第一个问题是使用新的

UserRepository
存储库创建新的块实例。如果您愿意,您可以创建单例类。

要访问当前的块实例,您可以使用

BlocProvider.of<UserBloc>(context);

   final bloc = BlocProvider.of<UserBloc>(context);
   bloc.add(LoadUserEvent());

您无法访问与您创建的块相同的上下文。您可以使用 Builder 或新的小部件来实现单独的上下文。

现在,当我们获取数据时,旧数据会被新数据替换,而不是扩展列表。因此我正在修改块,例如

class UserBloc extends Bloc<UserEvent, UserState> {
  final UserRepository _userRepository;
  final String pageNo; //I prefer using event for this.
  UserBloc(this._userRepository, this.pageNo) : super(UserLoadingState()) {
    on<LoadUserEvent>((event, emit) async {
      // emit(UserLoadingState()); //not needed, else we need to lift up the old user list
      debugPrint("pageNo $pageNo");
      try {
        final users = await _userRepository.getUsers(pageNo);
        List<UserModel> oldUser = []; //get the old user list
        if (state is UserLoadedState) {
          oldUser = (state as UserLoadedState).users;
          debugPrint("oldUser.length ${oldUser.length}");
        }
        emit(UserLoadedState([...oldUser, ...users]));
      } catch (e) {
        emit(UserErrorState(e.toString()));
      }
    });
  }
}

完整片段

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:http/http.dart';
import 'dart:convert';
import 'package:equatable/equatable.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  String pageNo = "1";
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<UserBloc>(
          create: (BuildContext context) => UserBloc(UserRepository(), pageNo)
            ..add(LoadUserEvent()), //initially load the user
        ),
      ],
      child: Builder(
        builder: (context) {
          /// you cant directly access the bloc from here, so use builder or new widget
          return Scaffold(
            appBar: AppBar(title: const Text('The BloC App')),
            body: blocBody(),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                final bloc = BlocProvider.of<UserBloc>(context);
                var pageNo = "2";
                bloc.add(LoadUserEvent());
              },
              child: const Icon(Icons.navigation),
            ),
          );
        },
      ),
    );
  }

  Widget blocBody() {
    return BlocBuilder<UserBloc, UserState>(
      builder: (context, state) {
        if (state is UserLoadingState) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
        if (state is UserLoadedState) {
          List<UserModel> userList = state.users;
          debugPrint("userList.length ${userList.length}");
          return ListView.builder(
              itemCount: userList.length,
              itemBuilder: (_, index) {
                return Padding(
                  padding:
                      const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
                  child: Card(
                    color: Theme.of(context).primaryColor,
                    child: ListTile(
                      title: Text(
                        '${userList[index].firstName}  ${userList[index].lastName}',
                        style: const TextStyle(color: Colors.white),
                      ),
                      subtitle: Text(
                        '${userList[index].email}',
                        style: const TextStyle(color: Colors.white),
                      ),
                      leading: CircleAvatar(
                          // backgroundImage:
                          //     NetworkImage(userList[index].avatar.toString()),
                          ),
                    ),
                  ),
                );
              });
        }
        if (state is UserErrorState) {
          return const Center(
            child: Text("Error"),
          );
        }

        return Container();
      },
    );
  }
}

class UserBloc extends Bloc<UserEvent, UserState> {
  final UserRepository _userRepository;
  final String pageNo;
  UserBloc(this._userRepository, this.pageNo) : super(UserLoadingState()) {
    on<LoadUserEvent>((event, emit) async {
      // emit(UserLoadingState()); //not needed, else we need to lift up the old user list
      debugPrint("pageNo $pageNo");
      try {
        final users = await _userRepository.getUsers(pageNo);
        List<UserModel> oldUser = []; //get the old user list
        if (state is UserLoadedState) {
          oldUser = (state as UserLoadedState).users;
          debugPrint("oldUser.length ${oldUser.length}");
        }
        emit(UserLoadedState([...oldUser, ...users]));
      } catch (e) {
        emit(UserErrorState(e.toString()));
      }
    });
  }
}

@immutable
abstract class UserEvent extends Equatable {
  const UserEvent();
}

class LoadUserEvent extends UserEvent {
  @override
  List<Object?> get props => [];
}

@immutable
abstract class UserState extends Equatable {}

//data loading state
class UserLoadingState extends UserState {
  @override
  List<Object?> get props => [];
}

class UserLoadedState extends UserState {
  final List<UserModel> users;
  UserLoadedState(this.users);
  @override
  List<Object?> get props => [users];
}

class UserErrorState extends UserState {
  final String error;
  UserErrorState(this.error);
  @override
  List<Object?> get props => [error];
}

class UserModel { //also prefer extending Equatable
  int? id;
  String? email;
  String? firstName;
  String? lastName;
  String? avatar;

  UserModel({this.id, this.email, this.firstName, this.lastName, this.avatar});

  UserModel.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    email = json['email'];
    firstName = json['first_name'];
    lastName = json['last_name'];
    avatar = json['avatar'];
  }

}

class UserRepository {
  String userUrl = 'https://reqres.in/api/users?page=';

  Future<List<UserModel>> getUsers(String pageNo) async {
//     Response response = await get(Uri.parse(userUrl+pageNo));
//
//     if (response.statusCode == 200) {
//       final List result = jsonDecode(response.body)['data'];
//       return result.map((e) => UserModel.fromJson(e)).toList();
//     } else {
//       throw Exception(response.reasonPhrase);
//     }

    return List.generate(
        3,
        (index) => UserModel(
            id: index,
            email: "email",
            firstName: "firstName",
            lastName: "lastName",
            avatar: "avatar"));
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.