Search code examples
flutterriverpod

Flutter Riverpod updating state issue


The state is not updating while the value in the print statement is updating. I don't know if I had used the correct way of the Counter class or not please help me.

here is my code :

import 'package:flutter_riverpod/flutter_riverpod.dart';


class numbers{
  int value1 = 0;
  int value2 = 0;
}

class Counter extends StateNotifier<numbers> {
  Counter(super.state);
  void add1()
  {
    state.value1++;
    print(state.value1.toString() + ' FromClass');
  }
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'Counter.dart';

final counterProvider = StateNotifierProvider<Counter, numbers>((ref)=>Counter(numbers()));

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends ConsumerWidget {



  @override
  Widget build(BuildContext context,WidgetRef ref) {
    var count = ref.watch(counterProvider.notifier).state.value1;
    return MaterialApp(home: Scaffold(body: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Center(child: Container(child: Text(count.toString()),),),
      ElevatedButton(onPressed: (){
        ref.read(counterProvider.notifier).state.value1++;
        print(ref.read(counterProvider.notifier).state.value1);
        //print(count.readValue1());
      }, child: Text('+'))],),),);
  }
}

Make the state updating after pressing + button


Solution

  • First of all, I converted your `Numbers' model. First of all, it must be immutable and with correctly redefined ==/hashCode. To make such models easily, take a closer look at the freezed package.

    @immutable
    class Numbers {
      const Numbers({this.value1 = 0, this.value2 = 0});
    
      final int value1;
      final int value2;
    
      Numbers copyWith({
        int? value1,
        int? value2,
      }) {
        return Numbers(
          value1: value1 ?? this.value1,
          value2: value2 ?? this.value2,
        );
      }
    
      @override
      bool operator ==(Object other) =>
          identical(this, other) ||
          other is Numbers &&
              runtimeType == other.runtimeType &&
              value1 == other.value1 &&
              value2 == other.value2;
    
      @override
      int get hashCode => value1.hashCode ^ value2.hashCode;
    }
    

    Your Counter class will look like this:

    final counterProvider =
        StateNotifierProvider<Counter, Numbers>((ref) => Counter(const Numbers()));
    
    class Counter extends StateNotifier<Numbers> {
      Counter(super.state);
      void add1() {
        state = state.copyWith(value1: state.value1 + 1);
        print('${state.value1} Counter.add1');
      }
    }
    

    And the interface is converted as follows:

    class MyApp extends ConsumerWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final count1 = ref.watch(counterProvider.select((value) => value.value1));
    
        return MaterialApp(
          home: Scaffold(
            body: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Center(child: Text(count1.toString())),
                ElevatedButton(
                    onPressed: () {
                      ref.read(counterProvider.notifier).add1();
                      print(ref.read(counterProvider.notifier).state.value1);
                    },
                    child: const Text('+'))
              ],
            ),
          ),
        );
      }
    }
    

    I purposely used select so that changing the value of value2 would not trigger a rebuild. If you need to keep track of the entire state of Numbers use a simple ref.wacth(counterProvider) in the build method:

    final Numbers counter = ref.watch(counterProvider);
    counter.value1;