Provider: Trouble with ChangeNotifierProxyProvider

Created on 5 Feb 2020  路  5Comments  路  Source: rrousselGit/provider

Hello!
Met an issue with ChangeNotifierProxyProvider
Here is a snippet of a simple program
It adds 1 to a random generated number (from 1 to 10) and writes an equation in form like '5 + 1 = 6'
But Provider2 is not getting correct number from Provider1 (provider: ^4.0.2)

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class Provider1 with ChangeNotifier {
  // Generates random number from 1 to 10

  int randN = 0;

  void generateRandomNumber() {
    randN = Random().nextInt(10);
    print(randN);
    notifyListeners();
  }
}

class Provider2 with ChangeNotifier {
  // Adds 1 to early generated number

  int increasedN;

  Provider2(this.increasedN);

  void increaseByOne() {
    increasedN = increasedN + 1;
    print(increasedN);
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Provider1(),
        ),
        ChangeNotifierProxyProvider<Provider1, Provider2>(
          create: null,
          update: (_, prov1, __) => Provider2(prov1.randN),
        ),
      ],
      child: MaterialApp(
        title: 'Demo',
        home: Home(),
      ),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo'),
      ),
      body: Column(
        children: <Widget>[
          Text(
              '${Provider.of<Provider1>(context).randN} + 1 = ${Provider.of<Provider2>(context).increasedN}'),
          RaisedButton(
            onPressed: () {
              Provider.of<Provider1>(context, listen: false)
                  .generateRandomNumber();
              Provider.of<Provider2>(context, listen: false)
                  .increaseByOne(); // if remove 'listen: false' - get error
            },
            child: Text('Generate Random Number'),
          ),
        ],
      ),
    );
  }
}

Sorry if it's an obvious problem, but i cannot see solution and spent too much time on it already

[鉁揮 Flutter (Channel master, v1.14.7-pre.103, on Linux, locale en_US.UTF-8)
[鉁揮 Android toolchain - develop for Android devices (Android SDK version 29.0.1)
[鉁揮 Android Studio (version 3.4)
[鉁揮 VS Code (version 1.41.1)
[鉁揮 Connected device (1 available)

Most helpful comment

Calling increment inside update without any sort of condition is a bad idea

You have to make sure that the value changed

All 5 comments

Hi, sorry i had no time to try your code but this might help:

MultiProvider(
      providers: [
        ChangeNotifierProvider(
          builder: (_, __) => Provider1(),
        ),
        ChangeNotifierProxyProvider<Provider1, Provider2>(
          create: (context) => Provider2(Provider.of<Provider1>(context, listen: false).randN),
          update: (_, prov1, prev) => prev..increaseByOne(prov1.randN),
        ),
      ],
void increaseByOne(int randN) {
    increasedN = randN + 1;
    print(increasedN);
    notifyListeners();
  }

@smiLLe Thanks, it worked!

But now increaseByOne() function is executing 2 times
And is there a way to not pass prov1.randN directly to increaseByOne function?

Because now there is a line

Provider.of<Provider2>(context, listen: false).increaseByOne(Provider.of<Provider1>(context, listen: false).randN);

And it looks too complicated

Whole working code is here

```import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class Provider1 with ChangeNotifier {
// Generates random number from 1 to 10

int randN = 0;

void generateRandomNumber() {
randN = Random().nextInt(10);
print(randN);
notifyListeners();
}
}

class Provider2 with ChangeNotifier {
// Adds 1 to early generated number

int increasedN;

Provider2(this.increasedN);

void increaseByOne(int randN) {
increasedN = randN + 1;
print(increasedN);
notifyListeners();
}
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Provider1(),
),
ChangeNotifierProxyProvider(
create: (context) =>
Provider2(Provider.of(context, listen: false).randN),
update: (_, prov1, prev) => prev..increaseByOne(prov1.randN),
),
],
child: MaterialApp(
title: 'Demo',
home: Home(),
),
);
}
}

class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Column(
children: [
Text(
'${Provider.of(context).randN} + 1 = ${Provider.of(context).increasedN}'),
RaisedButton(
onPressed: () {
Provider.of(context, listen: false)
.generateRandomNumber();
Provider.of(context, listen: false).increaseByOne(
Provider.of(context, listen: false)
.randN);
},
child: Text('Generate Random Number'),
),
],
),
);
}
}
```

Calling increment inside update without any sort of condition is a bad idea

You have to make sure that the value changed

Closing this since it seems to be solved.

Thanks, I understood what was wrong
Sorry for late response
Here is correct code if someone needs it

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class Provider1 with ChangeNotifier {
  int randN = 0;

  void generateRandomNumber() {
    randN = Random().nextInt(10);
    notifyListeners();
  }
}

class Provider2 with ChangeNotifier {
  int increasedN;

  void increaseByOne(int randN) {
    increasedN = randN + 1;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Provider1(),
        ),
        ChangeNotifierProxyProvider<Provider1, Provider2>(
          create: (context) => Provider2(),
          update: (_, prov1, prov2) => prov2..increaseByOne(prov1.randN),
        ),
      ],
      child: MaterialApp(
        title: 'Demo',
        home: Home(),
      ),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo'),
      ),
      body: Column(
        children: <Widget>[
          Text(
              '${Provider.of<Provider1>(context).randN} + 1 = ${Provider.of<Provider2>(context).increasedN}'),
          RaisedButton(
            onPressed: () {
              Provider.of<Provider1>(context, listen: false)
                  .generateRandomNumber();
            },
            child: Text('Generate Random Number'),
          ),
        ],
      ),
    );
  }
}

Was this page helpful?
0 / 5 - 0 ratings