Reputation: 28886
ParentPage
:
class ParentPage extends StatefulWidget {
@override
ParentPageState createState() => ParentPageState();
}
class ParentPageState<T extends ParentPage> extends State<T> {
int counter = 0;
void incrementCounter() => setState(() => counter++);
@override
Widget build(BuildContext context) => Text('$counter'); // Not updating
}
ChildPage
:
class ChildPage extends ParentPage {
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends ParentPageState<ChildPage> {
@override
Widget build(BuildContext context) {
print('build[$counter]'); // Updates
return Scaffold(
body: ParentPage(),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Icon(Icons.add),
),
);
}
}
I'm using home: ChildPage()
in my MaterialApp
widget.
Problem:
When I click on the FAB, it increments counter
(which can be seen in the print statement of _ChildPageState.build
method) but the Text
widget in ParentPage
stays at 0
. Why is that so?
Upvotes: 0
Views: 90
Reputation: 7298
It stays at 0 because the call to setState()
you are doing will update the state of _ChildPageState
and not the state of your body: ParentPage()
as it is a different instance.
Same goes for your print('build[$counter]');
it will display the correct value because it is the counter
variable of your _ChildPageState
and not the one from your ParentPage()
.
_ChildPageState
by extending your ParentPageState<ChildPage>
has a counter
variable and an incrementCounter()
method.
The same goes for body: ParentPage()
, as it is a new instance of ParentPage
it has its own counter
and incrementCounter()
.
By calling incrementCounter
in your code like this:
class _ChildPageState extends ParentPageState<ChildPage> {
@override
Widget build(BuildContext context) {
// ...
return Scaffold(
// ...
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter, // Here
child: Icon(Icons.add),
),
);
}
}
You are refering to the incrementCounter
method from your _ChildPageState
to increment the counter
value of _ChildPageState
. This is why print('build[$counter]');
updates itself correctly as it is the counter
from _ChildPageState
.
Now for your body: ParentPage()
, as I've said, it has its own properties and methods, which means that its method incrementCounter
is never called and its counter
value will never be incremented.
class ParentPage extends StatefulWidget {
final String pageId;
const ParentPage({required this.pageId});
@override
ParentPageState createState() => ParentPageState();
}
class ParentPageState<T extends ParentPage> extends State<T> {
int counter = 0;
void incrementCounter() {
print('Update counter from: ${widget.pageId}');
setState(() => counter++);
}
@override
Widget build(BuildContext context) => Text('$counter'); // Not updating
}
class ChildPage extends ParentPage {
const ChildPage() : super(pageId: 'ChildPage');
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends ParentPageState<ChildPage> {
@override
Widget build(BuildContext context) {
print('build[$counter]'); // Updates
return Scaffold(
body: const ParentPage(pageId: 'Body Page'),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: const Icon(Icons.add),
),
);
}
}
build[0]
Update counter from: ChildPage // First Tap
build[1]
Update counter from: ChildPage // Second Tap
build[2]
As you can see the incrementCounter
from ParentPage(pageId: 'Body Page')
is never called to increment its counter
.
Upvotes: 1
Reputation: 12565
Please try with custom widget
Parent page:
import 'package:flutter/material.dart';
class ParentPage extends StatefulWidget {
@override
ParentPageState createState() => ParentPageState();
}
class ParentPageState<T extends ParentPage> extends State<T> {
int counter = 0;
void incrementCounter() => setState(() => counter++);
body() {
return Center(child: Text('$counter'));
}
@override
Widget build(BuildContext context) => body();
}
child page:
import 'package:flutter/material.dart';
import 'package:so_test/model/list_model.dart';
class ChildPage extends ParentPage {
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends ParentPageState<ChildPage> {
@override
body() {
return Scaffold(
body: Center(child: Text("$counter"),),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Icon(Icons.add),
),
);
}
}
So, this basically means that the BuildContext inside the build() method is actually that of it's parent. Hence, their is no need to explicitly pass it.
Upvotes: 0
Reputation: 17
When building ChildPage you create a new instance of ParentPage.
body: ParentPage(),
That is a separate instance, so it has its own state.
It's just if you had for example 2 different Containers - you would not expect them to have the same properties just because they use the same class.
You can test it by checking the value of counter
in the child widget.
class ChildPage extends ParentPage {
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends ParentPageState<ChildPage> {
@override
Widget build(BuildContext context) {
print('build[$counter]'); // Updates
return Scaffold(
body: Column(children: [ParentPage(), Text('$counter'),]),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Icon(Icons.add),
),
);
}
}
Upvotes: 1