user14709104
user14709104

Reputation:

Flutter riverpod Change notifier not updating value

I'm using riverpod to manage states of some variables in my app like opacity, stroke width and color for my coloring app.

Here's my opacity class inside notifier.dart:

    class OpacityChangeNotifier extends ChangeNotifier {
      OpacityChangeNotifier([this.opacity = 1.0]);
      double opacity;
    
      void changeOpacity(double providedOpacity) {
        opacity = providedOpacity;
        notifyListeners();
      }
    
      void printOpacity() {
        print(opacity);
      }
    }

This is from my OpacityPicker.dart:

final _opacityProvider = ChangeNotifierProvider<OpacityChangeNotifier>((ref) {
  return OpacityChangeNotifier();
});

class OpacityPicker extends ConsumerWidget {
  const OpacityPicker({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    return Container(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          IconButton(
            onPressed: () {
              context.read(_opacityProvider).changeOpacity(0.1);
              context.read(_opacityProvider).printOpacity();
            },
            icon: Icon(Icons.opacity, size: 20),
          ),
          IconButton(
            onPressed: () {
              context.read(_opacityProvider).changeOpacity(0.5);
              context.read(_opacityProvider).printOpacity();
            },
            icon: Icon(Icons.opacity, size: 30),
          ),
          IconButton(
            onPressed: () {
              context.read(_opacityProvider).changeOpacity(1.0);
              context.read(_opacityProvider).printOpacity();
            },
            icon: Icon(Icons.opacity, size: 40),
          ),
        ],
      ),
    );
  }
}

finally this is my menu_items.dart:

final _opacityChangeProvider =
    ChangeNotifierProvider<OpacityChangeNotifier>((ref) {
  return OpacityChangeNotifier();
});

class UtilityItems extends ConsumerWidget {
  const UtilityItems({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final opacityNotifier = watch(_opacityChangeProvider);
    return SingleChildScrollView(
      child: Container(
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                IconButton(
                  onPressed: () {
                    print(opacityNotifier.opacity);
                  },
                  icon: Icon(Icons.dock_rounded),
                )
              ],
            ),
            OpacityPicker(),
          ],
        ),
      ),
    );
  }
}

Everything is working fine inside OpacityPicker.dart. When I'm pressing the opacity button the selected opacity is getting printed. But when I'm pressing the Icons.dock_rounded in menu_items.dart shouldn't I get the updated value?

It's showing the default value for opacity which is 1.0

I've looked it up and all I got was some issues related to changeNotifier not working back in September 2020.

What am I missing here?

N.B: I've imported all the files correctly. And I want the value of opacity to change to the user selected one on pressed. So I need my menu_item.dart widget to know that.

Upvotes: 1

Views: 3005

Answers (1)

Alex Hartford
Alex Hartford

Reputation: 6000

Building off @puelo comment, you shouldn't be redefining your ChangeNotifierProvider. The way you have it is two isolated providers with two separate ChangeNotifiers that have no knowledge of eachother.

I would recommend making provider a static member of your ChangeNotifier like so:

class OpacityChangeNotifier extends ChangeNotifier {
  OpacityChangeNotifier([this.opacity = 1.0]);
  
  static final provider = ChangeNotifierProvider<OpacityChangeNotifier>((ref) {
    return OpacityChangeNotifier();
  });

  double opacity;
    
  void changeOpacity(double providedOpacity) {
    opacity = providedOpacity;
    notifyListeners();
  }
    
  void printOpacity() {
    print(opacity);
  }
}

To access:

context.read(OpacityChangeNotifier.provider);

This helps to keep your imports clean as well as avoiding redundant naming and reduces the likelihood someone else working on the project would end up creating another provider for that notifier.

Use that provider instead of defining it twice and that should solve your primary issue.

You should also always use context.read inside function handlers like onPressed. In your menu_items.dart you should refactor as follows:

class UtilityItems extends ConsumerWidget {
  const UtilityItems({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    return SingleChildScrollView(
      child: Container(
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                IconButton(
                  onPressed: () {
                    final opacity = context.read(OpacityChangeNotifier.provider).opacity;
                    print(opacity);
                  },
                  icon: Icon(Icons.dock_rounded),
                )
              ],
            ),
            OpacityPicker(),
          ],
        ),
      ),
    );
  }
}

Upvotes: 1

Related Questions