Home > OS >  Flutter setState function doesn't work when used to change class member
Flutter setState function doesn't work when used to change class member

Time:11-11

i have the following codes,

class mWidget extends StatefulWidget {
  mWidget({super.key, required this.text});
  String text;

  @override
  State<mWidget> createState() => _mWidgetState();
}

class _mWidgetState extends State<mWidget> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(widget.text),
    );
  }
}

This is my custom widget,

class _MainState extends State<Main> {
  var n = mWidget(text: "Hi");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          n,
          ElevatedButton(
            onPressed: () {
              setState(() {
                n.text = "Hello";
              });
            },
            child: Text("Click me"),
          ),
        ],
      ),
    );
  }
}

And this is the code in the main.dart file.

The problem is that pressing the button doesn't change the output on the screen unless a hot reload even though I am calling the setState function.

I wonder why is that.

Thanks in advance!

CodePudding user response:

You can reinitialize the n on easy approach like

   n = mWidget(text: "Hello");

Or use state-management property like riverpod/bloc. callback method may also help. I am using ValueNotifier, you dont need to make theses statefulWidget


class Main extends StatefulWidget {
  const Main({super.key});

  @override
  State<Main> createState() => _MainState();
}

class _MainState extends State<Main> {
  final ValueNotifier textNotifier = ValueNotifier('Hi');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          mWidget(text: textNotifier),
          ElevatedButton(
            onPressed: () {
              setState(() {
                textNotifier.value = "Hello";
              });
            },
            child: Text("Click me"),
          ),
        ],
      ),
    );
  }
}

class mWidget extends StatefulWidget {
  mWidget({super.key, required this.text});
  ValueNotifier text;

  @override
  State<mWidget> createState() => _mWidgetState();
}

class _mWidgetState extends State<mWidget> {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: ValueListenableBuilder(
      valueListenable: widget.text,
      builder: (context, value, child) => Text(value),
    ));
  }
}

CodePudding user response:

You made a couple of mistakes in this!

In your code, you made a widget named mWidget and created an instance of it, it is not the right approach to access any widget using an instance, as state of instances cannot be updated.

You are using the state of mWidget outside of its scope, where it is not accessible.

You can use keys to achieve what you want. (It is not advisable to use this for large-scale project)

Here is a small code which can help you to achieve the functionality you want.

class mWidget extends StatefulWidget {
  mWidget({Key? key, required this.text}) : super(key: key);
  String text;

  @override
  State<mWidget> createState() => _mWidgetState();
}

class _mWidgetState extends State<mWidget> {
  String text = "";

  @override
  void initState() {
    text = widget.text;
    super.initState();
  }

  void updateValue(String newData) {
    setState(() {
      text = newData;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(text),
    );
  }
}


class _Main extends StatefulWidget {
  const _Main({Key? key}) : super(key: key);

  @override
  State<_Main> createState() => _MainState();
}

class _MainState extends State<_Main> {
  GlobalKey<_mWidgetState> _mWidgetStateKey = GlobalKey(); // This is the key declaration of _mWidgetState type

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          mWidget(text: "Hi", key: _mWidgetStateKey),
          ElevatedButton(
            onPressed: () =>
                _mWidgetStateKey.currentState!.updateValue("Hello"), // Calling the method of _mWidgetState class.
            child: Text("Click me"),
          ),
        ],
      ),
    );
  }
}
  • Related