Reputation: 195
I want to Extract a Widget with onPressed
setState
inside but I get the Message "Reference to an enclosing class method cannot be extracted."
Is there a way to do that?
I would like to divide my code into different widgets so that it remains clear. Here is simplified an example of the code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
@override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
TextOutput(myValue: myValue),
],
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
@required this.myValue,
}) : super(key: key);
final int myValue;
@override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
The part I want to extract into a separate widget:
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
Upvotes: 4
Views: 3416
Reputation: 1
in flutter: extracting a widget
"A reference to an enclosing class method can't be extracted," ERROR
this happens when the widget we are trying to extract uses setState
(which is specific to statefull widgets)
and it means = NO ACCESS TO setState method
HOW TO FIX THIS?
b-1: Extract with a callBack: The widget is stateful, but it communicates state changes to its parent via the callback,this maintains a single source of truth for the state.
b-2: Extract without a callBack in this case every instance will have its own internal state(isolation). which leads to a difficulty for parent widget to control or access the state.
Mostly we either extract as a function, as a stateless widget, or as a statefull widget with a callback.
when to extract as a statefull widget without a callBack?
Upvotes: 0
Reputation: 948
Flutter offers VoidCallback and Function(x) (where x can be a different type) for callback-style events between child and parent widgets.
Simply You can pass Function onPressed;
via constructor
Here is your Extracted Container widget:
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, @required this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
And Here How to use it:
@override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
Your full code example
import 'package:flutter/material.dart';
class MyApp2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
@override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
}
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, @required this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
@required this.myValue,
}) : super(key: key);
final int myValue;
@override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
Upvotes: 6
Reputation: 63584
You can use VoidCallback
on extract widget to get onPressed
event
class MyContainer extends StatelessWidget {
final VoidCallback onTap;
const MyContainer({
Key? key,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: onTap,
child: Text(
'Button 001',
),
),
);
}
}
And use like
MyContainer(
onTap: () {
print("tapped");
setState(() {
calculate();
});
},
),
Upvotes: 0
Reputation: 12353
Setstate is related to the widget you want to refresh its state. If you extract it to another place, then setState refers to the state of the new widget.
In your case, the setState will only change the state of the container encapsulating your widget which you are trying to extract and its children, it doesn't migrate upward.
Unless, you look for the state of the widget you want, using exact type
, and then trigger the state there, but this is overkill, a lot harder, requires more code, than what you currently have.
Upvotes: 0