Flutter Riverpod Statenotifier should rebuild on map changes

Viewed 259

My statenotifier does not rebuild when the map changes. I think the issue is that the map is inside another class. I use riverpod and i've seen it work with lists so I tested with a List inside a class and filter rebuilds to that class. But no success

StateNotifier using copyWith to replace a map does not trigger rebuild
class Admin {
  const Admin({
    this.admin = const {},
  });

  final Map<int, List<String>> admin;

  Admin copyWith({
    Map<int, List<String>>? admin,
  }) {
    return Admin(
      admin: admin ?? this.admin,
    );
  }
}

class Member {
  const Member({
    this.wordOfTheDay = "",
    this.admin = const Admin(),
  });

  final Admin admin;
  final String wordOfTheDay;

  Member copyWith({
    Admin? admin,
    String? wordOfTheDay,
  }) {
    return Member(
      admin: admin ?? this.admin,
      wordOfTheDay: wordOfTheDay ?? this.wordOfTheDay,
    );
  }
}

class MemberNotifier extends StateNotifier<AsyncValue<Member>> {
  MemberNotifier() : super(const AsyncValue.loading());

  final Map<int, List<String>> admins = {};

  void loadMembers(String id, String item) {
    admins[id]!.add(item);
    state = state.whenData((value) => value.copyWith(admin: state.value!.admin.copyWith(admin: admins)));
  }
}

final watch = ref.watch(memberNotifierProvider.select((member) => member.value!.admin));
1 Answers

We can pass the Map values and set the values in Map<String,dynamic> like this:-

Provider

 final counterProvider =
        StateNotifierProvider<Counter, Map<String, dynamic>>((_) => Counter());

class Counter extends StateNotifier<Map<String, dynamic>> {
  // Counter(Map<String, dynamic> data): super(data);
  Counter() : super({});

  void displayFile(String name, String email, String address) {
    Map<String, dynamic> cartMap = {"name": name, "email": email, "address": address};

    state = {...state, ...cartMap};
  }
}

After that we can fetch the values of Map using this way in Riverpod with HooksConsumerWidget:-

class MyHomePage extends HookConsumerWidget {
  MyHomePage({Key? key}) : super(key: key);

  TextEditingController nameController = TextEditingController();
  TextEditingController emailController = TextEditingController();
  TextEditingController addressController = TextEditingController();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final dataValue = ref.watch(counterProvider);
    String name = dataValue['name'].toString();
    String email = dataValue['email'].toString();
    String address = dataValue['address'].toString();
    print(dataValue);
    return Scaffold(
        appBar: AppBar(
          title: const Text(' demo'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            children: [
              TextFormField(
                controller: nameController,
                keyboardType: TextInputType.text,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Enter name',
                ),
              ),
              const SizedBox(
                height: 10,
              ),
              TextFormField(
                controller: emailController,
                keyboardType: TextInputType.text,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Enter email',
                ),
              ),
              const SizedBox(
                height: 10,
              ),
              TextFormField(
                controller: addressController,
                keyboardType: TextInputType.text,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: 'Enter address',
                ),
              ),
              const SizedBox(
                height: 10,
              ),
              ElevatedButton(
                  onPressed: () {
                    ref.read(counterProvider.notifier).displayFile(
                        nameController.text,
                        emailController.text,
                        addressController.text);
                  },
                  child: const Text('Show Details')),
              const SizedBox(
                height: 20,
              ),
              Text(name),
              const SizedBox(
                height: 10,
              ),
              Text(email),
              const SizedBox(
                height: 10,
              ),
              Text(address),
            ],
          ),
        ));
  }
}
Related