Normally, I use a separate class with an object declared on the top of the widget. I wish to know what is the problem with that architecture.
I came across an entire package in Flutter, WidgetView, which needs to declare a dependency, then make a state object, and then do the same thing.
Why not just a simple class for achieving the same. like below
class NewAccountComponent extends StatelessWidget {  
final NewAccountComponentLogic logic = NewAccountComponentLogic();
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Enter a Unique Account Number'),
      titlePadding: EdgeInsets.all(20.0),
      content: TextFormField(
        controller: logic.controller,
            onPressed: () => logic.clearTextFormField(),
          ),
        ),
}
class NewAccountComponentLogic {
  static String accountNumber;
  static bool existsAccountNumber;
  TextEditingController controller = TextEditingController();
  clearTextFormField() {
    controller.text = '';
    accountNumber = '';
}
You can separate widget logic and presentation in many ways. One that I've seen (and that you mention) is using the WidgetView pattern. You can do it without any dependency:
For Stateless widgets:
abstract class StatelessView<T1> extends StatelessWidget {
  final T1 widget;
  const StatelessView(this.widget, {Key key}) : super(key: key);
  
  @override
  Widget build(BuildContext context);
}
For Stateful widgets:
abstract class WidgetView<T1, T2> extends StatelessWidget {
  final T2 state;
  T1 get widget => (state as State).widget as T1;
  const WidgetView(this.state, {Key key}) : super(key: key);
  
  @override
  Widget build(BuildContext context);
}
// Note it's a StatefulWidget because accountNumber mutates
class NewAccountComponent extends StatefulWidget {
  @override
  _NewAccountComponentState createState() => _NewAccountComponentState();
}
class _NewAccountComponentState extends State<NewAccountComponent> {
  String accountNumber;
  bool existsAccountNumber;
  final TextEditingController controller = TextEditingController();
  clearTextFormField() {
    controller.text = '';
    accountNumber = '';
  }
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Enter a Unique Account Number'),
      titlePadding: EdgeInsets.all(20.0),
      content: TextFormField(
        controller: controller,
        onSaved: (value) => clearTextFormField(),
      ),
    );
  }
}
Statefulclass NewAccountComponent extends StatefulWidget {
  @override
  _NewAccountComponentController createState() => _NewAccountComponentController();
}
// State suffix renamed to Controller
// This class has all widget logic
class _NewAccountComponentController extends State<NewAccountComponent> {
  String accountNumber;
  bool existsAccountNumber;
  final TextEditingController controller = TextEditingController();
  clearTextFormField() {
    controller.text = '';
    accountNumber = '';
  }
  // In build, returns a new instance of your view, sending the current state
  @override
  Widget build(BuildContext context) => _NewAccountComponentView(this);
}
// View extends of WidgetView and has a current state to access widget logic
// with widget you can access to StatefulWidget parent
class _NewAccountComponentView
    extends WidgetView<NewAccountComponent, _NewAccountComponentController> {
  _NewAccountComponentView(_NewAccountComponentController state): super(state);
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Enter a Unique Account Number'),
      titlePadding: EdgeInsets.all(20.0),
      content: TextFormField(
        controller: state.controller,
        onSaved: (value) => state.clearTextFormField(),
      ),
    );
  }
}
class MyStatelessWidget extends StatelessWidget {
  final String textContent = "Hello!";
  const MyStatelessWidget({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(textContent),
    );
  }
}
to:
// Widget and logic controller are unit
class MyStatelessWidget extends StatelessWidget {
  final String textContent = "Hello!";
  const MyStatelessWidget({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) => _MyStatelessView(this);
}
// The view is separately
class _MyStatelessView extends StatelessView<MyStatelessWidget> {
  _MyStatelessView(MyStatelessWidget widget) : super(widget);
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(widget.textContent),
    );
  }
}
References:
Flutter: WidgetView — A Simple Separation of Layout and Logic
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