How to use stateful widget parameters in state class at construction without adding the widget to the tree? - flutter

I stumped into a problem where I need to use a StatefulWidget parameter in its state class when it's constructed, but I couldn't find a way to do it since using widget.[whatever variable name] in the state's class constructor returns an unexpected null value, and the initState function only runs when the widget is being drawn to the screen.
For example:
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
final String text;
Test(this.text);
final state = _TestState();
#override
_TestState createState() => state;
}
class _TestState extends State<Test> {
String? changingText;
void updateChangingText(String moreText){
changingText = changingText! + moreText;
}
#override
void initState() {
super.initState();
changingText = widget.text;
}
#override
Widget build(BuildContext context) {
return Text(changingText!);
}
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
var w = Test('test');
w.state.updateChangingText(' text');
return MaterialApp(home: Scaffold(body:
Test('test text')
));
}
}
void main() {
runApp(App());
}
This doesn't work since changingText is being updated before initState gives it its initial value since it only runs when Text is being drawn to the screen and this:
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
final String text;
Test(this.text);
final state = _TestState();
#override
_TestState createState() => state;
}
class _TestState extends State<Test> {
String? changingText;
void updateChangingText(String moreText){
changingText = changingText! + moreText;
}
_TestState(){
changingText = widget.text;
}
#override
Widget build(BuildContext context) {
return Text(changingText!);
}
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
var w = Test('test');
w.state.updateChangingText(' text');
return MaterialApp(home: Scaffold(body:
Test('test text')
));
}
}
void main() {
runApp(App());
}
doesn't work either since you can't use widget.[whatever] in state class constructors (for some reason).
So what can I do to use widget parameters in the state class before the widget is drawn to the screen?
Thanks in advance for the help

You should use the initState method present in the State for this instead of the constructor
#override
void initState() {
changingText = widget.text;
super.initState();
}

Related

Update TextEditingController Text with Riverpod

I'm new to Riverpod and am trying to migrate an app over from Provider. If I had a TextField and wanted to set its value based on my Provider model, I would do this:
class MyWidget extends StatefulWidget{
const MyWidget({ Key? key }) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var controller = TextEditingController();
#override
void didChangeDependencies() {
super.didChangeDependencies();
//Set the value here...
var model = Provider.of<Model>(context);
controller.text = model.name;
}
Widget build(BuildContext context) {
return TextField(controller: controller)
}
}
As I understand it, didChangeDependencies() would listen to changes from Provider.of<Model>(context) and update my controller accordingly.
I'm trying to pull off the same thing with Provider, but I can't ever get the TextField's value to show up.
class MyWidget extends ConsumerStatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
ConsumerState<ConsumerStatefulWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends ConsumerState<MyWidget> {
var controller = TextEditingController();
#override
void didChangeDependencies() {
super.didChangeDependencies();
//Trying the same thing here...
final name = ref.watch(providerName);
controller.text = name;
}
Widget build(BuildContext context) {
final name = ref.watch(providerName);
return Column(
children: [
//This doesn't work:
TextField(controller: controller),
//I know my provider has the value, because this works fine:
Text(name),
]
}
}
How can I get my TextEditingController's text property to update?
From Riverpod official website
///1.Create a [StateNotifier] sub-class, StateNotifier is something where you can define functions that can change your state like in this state is of String type, you also can use objects (Classes instead of primitive types)
class Counter extends StateNotifier<String> {
Counter() : super('');
void changeText(String text){
state=text;
}
///2.Create a provider [StateNotifierProvider] with this you can use in your widget
final counterProvider = StateNotifierProvider<Counter, String>((ref) {
return Counter();
});
///3.Consume the Provider this is how we can attach state with our widget
class Home extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final text = ref.watch(counterProvider);
return Text('$text');
}
}
so here you can add you widget like button and onTap executes the code like
onTap()=>changeText(textController.text);
So your text [Text('$text');] will automatically change.
String inputText = controller.text;

How to update statefulWidget data?

Like the below code:
class TestWidget extends StatefulWidget {
String name;
TestWidget(this.name);
void updateName(String name) {
//how to update Text data
}
#override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<KMSelectionItem> {
#override
Widget build(BuildContext context) {
return Text(widget.name);
}
}
I want to change the text data through the method updateName. But I don't know how can do it.
you should use setState method for this purpose, this method updates the ui based on the changes made. insert the function code like this and declare the function inside your stateful widget. to update the text:
class _TestWidgetState extends State<KMSelectionItem> {
#override
Widget build(BuildContext context) {
return Text(widget.name);
}
void updateName() {
//how to update Text data
setState(() {
widget.name = YOUR_NEW_TEXT;
});
}
}
class TestWidget extends StatefulWidget {
String name;
TestWidget(this.name);
void updateName(String name) {
setState(() {
name ="updated_name";
});
}
#override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<KMSelectionItem> {
#override
Widget build(BuildContext context) {
return Text(widget.name);
}
}

super.initstate() not being called

Im a new flutter developer and have just started using the initState(). However, it seems like it never gets called, I tried all fixes I found on here, but none of them works! Here is a simplified example
import 'package:flutter/material.dart';
class example extends StatefulWidget {
#override
_State createState() => _State();
}
class _State extends State<example> {
#override
void Initstate() {
super.initState();
print('hello world');
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
The hello world never gets printed though!
initState is not supposed to be inside the build function. You can create the initState function by going to the line above #override before build(), type init, hit ctrl space and it will autocomplete. This would be the correct version:
class _State extends State<Example> {
#override
void initState() {
super.initState();
print('hello world');
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}

Mount a new state in Flutter

I'm new to Flutter. I have made a stateful widget that has multiple options for states, and I have no clue how to switch between them, or if it's even possible. Basically I have:
class SWidget extends StatefulWidget {
State<StatefulWidget> createState(){
return _State1();
}
}
class _State1 extends State<SWidget> {
...
}
class _State2 extends State<SWidget> {
...
}
I want SWidget to switch from _State1 to _State2
Sorry if I don't understand your question but state is often tied to UI. If you need new state then chances are you're wanting to display something different. In that case, you'd want to distinguish the two states (and their UI components) by placing them in their own stateful widgets. You can then switch between the two widgets in a stateful or stateless widget:
class SWidget extends StatelessWidget {
SWidget(this.condition);
final bool condition;
#override
Widget build(BuildContext context) {
return condition ? Foo() : Bar();
}
}
class Foo extends StatefulWidget {
#override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
var _foo = 'foo';
#override
Widget build(BuildContext context) {
return Text(_foo);
}
}
class Bar extends StatefulWidget {
#override
_BarState createState() => _BarState();
}
class _BarState extends State<Bar> {
var _bar = 'bar';
#override
Widget build(BuildContext context) {
return Text(_bar);
}
}
I don't think I've ever seen anyone actually switch the state object out from underneath a widget. You can though easily change a widget's state by calling setState and toggling between values that way too:
class SWidget extends StatefulWidget {
#override
_SWidgetState createState() => _SWidgetState();
}
class _SWidgetState extends State<SWidget> {
var _value = true;
#override
Widget build(BuildContext context) {
return Switch(
value: _value,
onChanged: (value) => setState(() => _value = value),
);
}
}

flutter - clear the widget cache

When I leave a page when I work with flutter and then re-enter it, the old values are saved.
I don't want this to happen.
For example, when I first enter:
int number = 1;
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
bool donus = true;
class _TestPageState extends State<TestPage> {
List<Todo> sorular = new List<Todo>();
#override
void initState() {
print(donus);
super.initState();
getTodos();
}
bool pressAttention = true;
String ileri = "İleri", geri = "Geri";
#override
Widget build(BuildContext context) {number++;
print(number);
output:1
Second entry to the page:
output:2
I do not know how to fix this.
The scope of your number variable is outside the scope of your page and its state.
number is essentially static or global, and its lifetime is tied to your application's. Tighten up its scope so that it is declared within your state class and initialise it in your initState method (for private non-final variables).
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
bool donus = true;
class _TestPageState extends State<TestPage> {
List<Todo> sorular = new List<Todo>();
int _number;
#override
void initState() {
_number = 1;
print(donus);
super.initState();
getTodos();
}
bool pressAttention = true;
String ileri = "İleri", geri = "Geri";
#override
Widget build(BuildContext context) {
_number++; // You probably don't want to increment every time you build,
// but I have no idea what you're using `number` for.
print(_number);
Your donus variable is also global, which is unlikely to be what you had intended. Dart is an object-oriented language; refer to the language tour for more details on classes, scope, etc.