I'm using Bloc library and noticed after yielding a new state my TextFormField
initialValue does not change.
My app is more complicated than this but I did a minimal example. Also tracking the state it is changing after pushing the events.
Bloc is supposed to rebuild the entire widget right. Am I missing something?
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:developer' as developer;
void main() {
runApp(MyApp());
}
enum Event { first }
class ExampleBloc extends Bloc<Event, int> {
ExampleBloc() : super(0);
@override
Stream<int> mapEventToState(Event event) async* {
yield state + 1;
}
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (_) => ExampleBloc(),
child: Builder(
builder: (contex) => SafeArea(
child: BlocConsumer<ExampleBloc, int>(
listener: (context, state) {},
builder: (context, int state) {
developer.log(state.toString());
return Scaffold(
body: Form(
child: Column(
children: [
TextFormField(
autocorrect: false,
initialValue: state.toString(),
),
RaisedButton(
child: Text('Press'),
onPressed: () {
context.bloc<ExampleBloc>().add(Event.first);
},
)
],
),
),
);
}),
),
),
),
);
}
}
pubspec.yaml
name: form
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
bloc: ^6.0.0
flutter_bloc: ^6.0.0
Edit
As @chunhunghan noted adding a UniqueKey solves this. I should have also mentioned that my case. the app emits events from the onChanged
method of two TextFormField
. This causes the Form to reset and remove the keyboard. autofocus does not work because there are two TextFormField
wgich emit events.
You can copy paste run full code 1 and 2 below
You can provide UniqueKey()
to Scaffold
or TextFormField
to force recreate
You can referecne https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d for detail
if the key of the Element doesn’t match the key of the corresponding Widget. This causes Flutter to deactivate those elements and remove the references to the Elements in the Element Tree
Solution 1:
return Scaffold(
key: UniqueKey(),
body: Form(
Solution 2:
TextFormField(
key: UniqueKey(),
working demo
full code 1 Scaffold
with UniqueKey
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:developer' as developer;
void main() {
runApp(MyApp());
}
enum Event { first }
class ExampleBloc extends Bloc<Event, int> {
ExampleBloc() : super(0);
@override
Stream<int> mapEventToState(Event event) async* {
yield state + 1;
}
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("build");
return MaterialApp(
home: BlocProvider(
create: (_) => ExampleBloc(),
child: Builder(
builder: (contex) => SafeArea(
child: BlocConsumer<ExampleBloc, int>(
listener: (context, state) {},
builder: (context, int state) {
print("state ${state.toString()}");
developer.log(state.toString());
return Scaffold(
key: UniqueKey(),
body: Form(
child: Column(
children: [
TextFormField(
autocorrect: false,
initialValue: state.toString(),
),
RaisedButton(
child: Text('Press'),
onPressed: () {
context.bloc<ExampleBloc>().add(Event.first);
},
)
],
),
),
);
}),
),
),
),
);
}
}
full code 2 TextFormField
with UniqueKey
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:developer' as developer;
void main() {
runApp(MyApp());
}
enum Event { first }
class ExampleBloc extends Bloc<Event, int> {
ExampleBloc() : super(0);
@override
Stream<int> mapEventToState(Event event) async* {
yield state + 1;
}
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("build");
return MaterialApp(
home: BlocProvider(
create: (_) => ExampleBloc(),
child: Builder(
builder: (contex) => SafeArea(
child: BlocConsumer<ExampleBloc, int>(
listener: (context, state) {},
builder: (context, int state) {
print("state ${state.toString()}");
developer.log(state.toString());
return Scaffold(
body: Form(
child: Column(
children: [
TextFormField(
key: UniqueKey(),
autocorrect: false,
initialValue: state.toString(),
),
RaisedButton(
child: Text('Press'),
onPressed: () {
context.bloc<ExampleBloc>().add(Event.first);
},
)
],
),
),
);
}),
),
),
),
);
}
}