8

I would like to ask for your help with this, please.

My sample code below aims to update the State of the Parent Widget from the Child Widget while also updating the Child Widget's State. The text value of the Parent Widget would update while also changing the color of the Child Widget's button.

import 'package:flutter/material.dart';

void main() => runApp(AppIndex());

class AppIndex extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: ParentWidget());
  }
}

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  String _textValue = 'Old Value';

callback(newValue){
  setState(() {
    _textValue = newValue;
  });
}

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(_textValue),
        ChildWidget(),
      ],
    );
  }
}

class ChildWidget extends StatefulWidget {
  String textValue;
  Function callback;

  ChildWidget({this.textValue, this.callback});

  @override
  _ChildWidgetState createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  bool buttonState = false;

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      color: buttonState == true ? Colors.greenAccent : Colors.redAccent,
      child: Text('Update State'),
      onPressed: () {
        setState(() {
          if (buttonState == false) {
            buttonState = true;
          } else if (buttonState == true) {
            buttonState = false;
          }
        });

        widget.callback('New Value');
      },
    );
  }
}

So far, what this is able to do is to update the color/state of the Child Widget, however, the Parent Widget doesn't seem to update its State. My original code, which this was take from, actually only updates the the Parent's State only but not both Parent and Child (same concept and concern).

The sample code above are derivatives of the results of my initial research before asking here.

I'm thinking there must be something wrong with how I structure my code or this is not possible with Flutter's Architecture based on how I made it. If possible, can you give me your recommendations for something with the same behavior? (Updating the Parent and Child States)

Sorry I am new to this type of programming and architecture.

AverageCoder
  • 321
  • 6
  • 15

1 Answers1

13

Welcome to Flutter! It seems like you're not passing the callback into the child widget. When instantiating the ChildWidget, you should do new ChildWidget(callback: this.callback); You can then access the value from the StatefulWidget from the State<ChildWidget> class using through the widget property, e.g. widget.callback.

Also, it's worth noting that you should try your best to avoid using the Function type, as it doesn't really provide information about what the Function will return, or what it will take as parameters. For this, Dart uses the typedef keyword. For example, for a function that takes a date string and returns a date (a somewhat contrived example, granted, given Darts excellent built-in support for dates), you can do the following:

typedef Date StringToDateParser(String datestring);

Then, in your class, you can use StringToDateParser as a type.

import 'package:flutter/material.dart';

void main() => runApp(AppIndex());

class AppIndex extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: ParentWidget());
  }
}

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  String _textValue = 'Old Value';

  callback(newValue){
    setState(() {
      _textValue = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(_textValue),
        ChildWidget(callback: this.callback, this._text),
      ],
    );
  }
}

class ChildWidget extends StatefulWidget {

  Function callback;

  ChildWidget({this.textValue, this.callback});

  @override
  _ChildWidgetState createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  bool buttonState = false;

  _ChildWidgetState();

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      color: buttonState == true ? Colors.greenAccent : Colors.redAccent,
      child: Text('Update State'),
      onPressed: () {
        setState(() {
          if (buttonState == false) {
            buttonState = true;
          } else if (buttonState == true) {
            buttonState = false;
          }
        });

        widget.callback('New Value');
      },
    );
  }
}
Spencer Stolworthy
  • 1,352
  • 10
  • 17
  • 1
    Thank you so much! That was quick. I realized my mistake now, you know I swear that this same thing didn't seem to work on my actual code (the concept that is). Your recommendation made me review it again (after a lot of lookups already) and found it to work. – AverageCoder Jan 21 '20 at 01:43
  • Hoping this isn't too much but can you enlighten me more with the State propagation that you mentioned? :) – AverageCoder Jan 21 '20 at 01:44
  • Hahaha, that's the curse of programming, the code never works until someone else looks at it, then Poof! magically it starts working :) Good luck. Flutters amazing. – Spencer Stolworthy Jan 21 '20 at 01:44
  • And of course, let me update my answer to include your code with the corrected edits. – Spencer Stolworthy Jan 21 '20 at 01:45
  • I've tried it and see what you mean now, but is there an advantage in passing down callback (like what you've mentioned) and calling it via this.callback() as opposed to calling it via widget.callback() like how I did? What I initially learned was what I have written down, maybe I can improve my code moving forward through this. :) – AverageCoder Jan 21 '20 at 02:11