Closed ConfidenceYobo closed 4 years ago
After leaving the page and re-navigate to the page BlocBuilder still keeps old state.
Here is my widget:
class CreateRoom extends StatefulWidget { @override _CreateRoomState createState() => _CreateRoomState(); } class _CreateRoomState extends State<CreateRoom> with SingleTickerProviderStateMixin { bool pressAttention = true; final _scrollController = ScrollController(); final _scrollThreshold = 200.0; InviteBloc _inviteBloc; final List<User> invitedUsers = []; String query; @override void initState() { super.initState(); _scrollController.addListener(_onScroll); _inviteBloc = BlocProvider.of<InviteBloc>(context); } @override Widget build(BuildContext context) { return BlocBuilder<InviteBloc, InviteState>( builder: (blocContext, state) { List _users = []; if (state is InviteSuccess) { _users = state.props[0]; } print('show state'); print(state); return Scaffold( backgroundColor: Colors.white, body: GestureDetector( onTap: () { FocusScope.of(context).requestFocus(new FocusNode()); }, child: NestedScrollView( controller: _scrollController, headerSliverBuilder: (BuildContext context, bool boxIsScrolled) { return <Widget>[ SliverAppBar( floating: false, pinned: true, elevation: 0, automaticallyImplyLeading: false, centerTitle: true, leading: IconButton( icon: Icon( Icons.arrow_back_ios, size: 18, color: CustomColor.black, ), onPressed: () { Navigator.pop(context); }), title: PageTitle( title: 'New Group', textStyle: TextStyle( color: CustomColor.black, fontFamily: 'CircularStd', fontWeight: FontWeight.w700, fontSize: 19.0, )), actions: <Widget>[ Row( children: <Widget>[ invitedUsers.isNotEmpty ? GestureDetector( child: Container( child: Padding( padding: const EdgeInsets.only( left: 25.0, top: 10, bottom: 10), child: Text( 'Next', style: TextStyle( color: CustomColor.primary, fontFamily: 'CircularStd', fontWeight: FontWeight.w600, fontSize: 16.0, ), ), ), ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => CreateRoomImageUpload( users: invitedUsers)), ); }, ) : Container(), SizedBox(width: 15) ], ), ], ), ]; }, body: SingleChildScrollView( physics: BouncingScrollPhysics(), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ SearchInput( placeHolderText: 'Search for people to invite', onChange: (text) { if (text.length > 0) { setState(() => query = text); _inviteBloc.add( InviteFetched(query: query, isSearching: true)); } }), state is InviteSuccess ? ListView.builder( physics: ClampingScrollPhysics(), shrinkWrap: true, scrollDirection: Axis.vertical, padding: EdgeInsets.symmetric(vertical: 0), itemCount: _users.length, itemBuilder: (BuildContext context, int index) { User _userDetails = _users[index]; return index >= _users.length ? BottomLoader() : UserInviteWidget( userDetails: _userDetails, onInvite: (user) => _inviteUser(user)); }, ) : Container(), ], ), ), ), ), ); }); } @override void dispose() { _scrollController.dispose(); super.dispose(); } void _onScroll() { if (query != null && query.length > 0) { final maxScroll = _scrollController.position.maxScrollExtent; final currentScroll = _scrollController.position.pixels; if (maxScroll - currentScroll <= _scrollThreshold) { _inviteBloc.add(InviteFetched(isSearching: false, query: query)); } } } void _inviteUser(user) { setState(() { user.isInvited ? invitedUsers.remove(user) : invitedUsers.add(user); user.isInvited = !user.isInvited; }); } }
My user model:
class User { int id; String username; String email; String profileImage; String gender; String city; bool roomInvite = false; bool roomMember = false; User( {this.id, this.username, this.profileImage, this.email, this.gender, this.city}); User.fromJson(Map<String, dynamic> parsedJson) : id = parsedJson['id'] ?? '', username = parsedJson['username'] ?? '', profileImage = parsedJson['profileImage'] ?? '', email = parsedJson['email'] ?? '', gender = parsedJson['gender'] ?? '', city = parsedJson['city'] ?? ''; Map<String, dynamic> toJson() { return <String, dynamic>{ "id": id, "username": username, "profileImage": profileImage, "email": email, "gender": gender, "city": city }; } set isInvited(bool invited) { this.roomInvite = invited; } bool get isInvited { return roomInvite; } set isRoomMember(bool roomMember) { roomMember = roomMember; } get isRoomMember { return roomMember; } @override String toString() => 'User { id: $id, username: $username, profileImage: $profileImage, ' + 'email: $email, gender: $gender, city: $city }'; }
My bloc is like:
import 'dart:async'; import 'package:bloc/bloc.dart'; import '../models/user.dart'; import '../services/rooms_repository.dart'; import 'package:meta/meta.dart'; import 'package:rxdart/rxdart.dart'; import 'bloc.dart'; class InviteBloc extends Bloc<InviteEvent, InviteState> { final RoomsRepository roomsRepository; InviteBloc({@required this.roomsRepository}) : super(InviteInitial()); @override Stream<Transition<InviteEvent, InviteState>> transformEvents( Stream<InviteEvent> events, TransitionFunction<InviteEvent, InviteState> transitionFn, ) { return super.transformEvents( events.debounceTime(const Duration(milliseconds: 500)), transitionFn, ); } @override Stream<InviteState> mapEventToState(InviteEvent event) async* { final currentState = state; if (event is InviteFetched && !_hasReachedMax(currentState)) { try { if (currentState is InviteInitial || event.isSearching) { yield* _getUsersOnInitialState(query: event.query); } if (currentState is InviteSuccess) { yield* _getUsersOnSuccessState(currentState, query: event.query, isSearching: event.isSearching); } } catch (e) { print(e); // yield InviteFailure(); } } } Stream<InviteState> _getUsersOnInitialState( {String query, bool isSearching}) async* { try { final initialPage = 1; final result = await _fetchUsersAndGetPages(initialPage, query: query); final users = result['users']; yield InviteSuccess( users: users, currentPage: result['currentPage'], lastPage: result['lastPage'], hasReachedMax: false); } catch (e) { print(e); // yield InviteFailure(); } } /// Takes the current state of the bloc, check if the nextPage (`currentState.currentPage + 1`) is beyond /// the lastPage (`nextPage > currentState.lastPage`). if it is setState to hasReachedMax /// else get the requested users and set in state Stream<InviteState> _getUsersOnSuccessState(currentState, {String query, bool isSearching}) async* { try { int nextPage = currentState.currentPage + 1; if (isSearching == false) { if (nextPage > currentState.lastPage) { yield currentState.copyWith(hasReachedMax: true); return; } } if (isSearching) { nextPage = 1; } final result = await _fetchUsersAndGetPages(nextPage, query: query); if (result == null) { return; } final users = result['users']; yield InviteSuccess( users: isSearching ? users : currentState.users + users, currentPage: result['currentPage'], lastPage: result['lastPage'], hasReachedMax: false, ); } catch (e) { print(e); // yield InviteFailure(); } } bool _hasReachedMax(InviteState state) => state is InviteSuccess && state.hasReachedMax; Future<Map<String, dynamic>> _fetchUsersAndGetPages(nextPage, {String query}) async { try { final response = await roomsRepository.getRoomInvite(page: nextPage, query: query); print('Getting response'); print(response); if (response == null) { return null; } final users = _users(response['results']); final int currentPage = response['pagination']['current_page']; final int lastPage = response['pagination']['last_page']; return {'users': users, 'currentPage': currentPage, 'lastPage': lastPage}; } catch (e) { print(e); throw Exception('error fetching users'); } } List _users(users) { return users.map((rawDetail) { return User( id: rawDetail['id'], username: rawDetail['username'], email: rawDetail['email'], profileImage: rawDetail['profile_image'], gender: rawDetail['gender'], city: rawDetail['city']); }).toList(); } }
I'm using:
flutter_bloc: ^6.0.1 equatable: ^1.0.0 meta: ^1.1.6 rxdart: ^0.23.1
Hi @ConfidenceYobo 👋
Could you create a minimal reproduction of your issue in a repo and share it ?
@RollyPeres https://github.com/ConfidenceYobo/bloc_demonstration is sample repo to demonstrate the issue.
Since your bloc is globally available it keeps state between your navigations, so it needs to be resetted with the help of an event, as you can see in this PR I've opened. Hope it helps 👍
After leaving the page and re-navigate to the page BlocBuilder still keeps old state.
Here is my widget:
My user model:
My bloc is like:
I'm using: