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);
},
)
],
),
),
);
}),
),
),
),
);
}
}
You should not be rebuilding the entire Form just because you want to update the value of the TextFormField, try using a TextEditingController and update the value on the listener.
TextEditingController _controller = TextEditingController();
BlocProvider(
create: (_) => ExampleBloc(),
child: Builder(
builder: (contex) => SafeArea(
child: BlocListener<ExampleBloc, int>(
listener: (context, state) {
_controller.text = state.toString();
},
child: Scaffold(
body: Form(
child: Column(
children: [
TextFormField(
controller: _controller,
autocorrect: false,
),
RaisedButton(
child: Text('Press'),
onPressed: () {
context.bloc<ExampleBloc>().add(Event.first);
},
)
],
),
),
);
}),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With