Skip to content

ValueNotifier does not notify listeners when modifying a list #29958

Closed

Description

@mikuhl-dev
import 'dart:math';

import 'package:flutter/material.dart';

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

ValueNotifier<List<String>> numbers = ValueNotifier(['123']);

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ValueListenableBuilder(
          valueListenable: numbers,
          builder: (BuildContext context, List<String> nums, Widget child) {
            return ListView.builder(
              itemCount: numbers.value.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(nums[index]),
                );
              },
            );
          },
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.star),
          onPressed: () {
            numbers.value.add(Random().nextInt(1000).toString());
          },
        ),
      ),
    );
  }
}

It looks like because the reference is the same, the notifiers are not called, for example, this works:

numbers.value = []..addAll(numbers.value)..add(Random().nextInt(1000).toString());

Activity

  1. jonahwilliams commented on Mar 26, 2019

    @jonahwilliams
    Contributor

    This class is a good candidate for better documentation

  2. alecorsino commented on Jun 7, 2019

    @alecorsino

    You answered your own question. ValueNotifier doesn't make all object down the object tree observables
    ValueNotifier<List<String>> numbers
    That's your observable value only.
    What it does is just create a setter like:
    set value(T newValue) { if (_value == newValue) return; _value = newValue; notifyListeners(); }
    notifyListeners(); will notify listeners when the reference of `numbers.value' changes and nothing else

  3. dsjgordon commented on Sep 6, 2019

    @dsjgordon

    This can be resolved by calling valueNotifier.notifyListeners() after updating the elements of the value.

    However, notifyListeners() is annotated as @protected, triggering IDE warnings. It would be nice if the annotation was removed as this issue describes a valid use-case to include it in the public interface.

  4. cgestes commented on Nov 3, 2019

    @cgestes
    Contributor

    Or we could modify the list in an immutable manner to ensure notifyListeners is called.

    For example:

    valueNotifier.value = List.from(valueNotifier.value)..add(...);
  5. esDotDev commented on Dec 12, 2019

    @esDotDev

    This would be nice to enable. Since ValueNotifier does not watch nested objects, a method should be provided to allow a developer to trigger manual notifications, in cases where we know we've modified some properties on the underlying value object.

  6. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Jan 27, 2020
  7. ianspryn commented on Apr 6, 2020

    @ianspryn

    Came here looking for a solution. A nice alternative to solve this might be Property Change Notifier. Use a custom add/remove method for a class that contains your list, and notify your listeners in those methods.

  8. Skyost commented on Apr 26, 2020

    @Skyost

    @ianspryn Property Change Notifier seems very good, but depending on a third party package just because there is a little @protected annotation is a bit annoying for me.

  9. gybin02 commented on May 26, 2020

    @gybin02

    This would be nice to enable valueNotifier.notifyListeners() for developer.

    this is like ObseravbleField from databinding in Android。

    Why not just refresh the widget associated with valueNotifier.
    And dispose them automatically when call super.disponse.

    eg:
    ObservableField firstName = new ObservableField<>();

  10. gskinner-shared commented on May 26, 2020

    @gskinner-shared

    The trick is to just extend ValueNotifier, and provide a public Notify fxn that calls NotifyListeners.

  11. apgapg commented on Oct 12, 2020

    @apgapg

    As per @gskinner-shared suggestion you can use this

    import 'package:flutter/material.dart';
    
    class PropertyValueNotifier<T> extends ValueNotifier<T> {
      PropertyValueNotifier(T value) : super(value);
    
      @override
      void notifyListeners() {
        super.notifyListeners();
      }
    }
    
  12. clragon commented on Jan 22, 2021

    @clragon

    that's not a bad solution, though it would still be alot nicer if it was like this by default.

  13. 14 remaining items

  14. clragon commented on Feb 10, 2022

    @clragon

    or, instead of writing that helperclass, you can use List.unmodifiable,
    so you always have to modify your list in an immutable manner.

  15. viniciusddrft commented on Mar 28, 2022

    @viniciusddrft

    I have this problem, I have a ValueNotifier<List> variable that stores image paths to make a slide but it fails with ValueNotifier but works with StreamController

      final ValueNotifier<List<String>> listImages = ValueNotifier([
        AppImages.backgroundHomeScreen2Body1,
        AppImages.backgroundHomeScreen2Body2,
        AppImages.backgroundHomeScreen2Body3
      ]);

    Here I just set my list

    ValueListenableBuilder(
                      valueListenable: listImages,
                      builder: (BuildContext context, List<String> images,
                          Widget? child) {
                        return Stack(
                          children: [
                            Padding(
                              padding: EdgeInsets.only(
                                left: _size.width * 0.06,
                                top: _size.height * 0.04,
                              ),
                              child: const Text(
                                '01 Crypto',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontFamily: 'Bronova',
                                ),
                              ),
                            ),
                            Padding(
                              padding: EdgeInsets.only(
                                  top: _size.height * 0.12, left: 0),
                              child: Image.asset(
                                images[0],
                                width: _size.width * 0.2,
                              ),
                            ),
                            Padding(
                              padding: EdgeInsets.only(
                                  top: _size.height * 0.10,
                                  left: _size.width * 0.02),
                              child: Image.asset(
                                images[1],
                                width: _size.width * 0.25,
                              ),
                            ),
                            Padding(
                              padding: EdgeInsets.only(
                                  top: _size.height * 0.05,
                                  left: _size.width * 0.052),
                              child: Image.asset(
                                images[2],
                                width: _size.width * 0.32,
                              ),
                            ),
                          ],
                        );
                      },
                    ),

    And here I passed the values ​​to the ValueListenableBuilder.

  16. carman247 commented on Apr 25, 2022

    @carman247

    Not sure why but I had to use the spread operator

    e.g.

    _notifier.value = [..._list];
    
  17. added
    P2Important issues not at the top of the work list
    on Feb 7, 2023
  18. self-assigned this
    on Mar 16, 2023
  19. github-actions commented on Apr 6, 2023

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  20. locked as resolved and limited conversation to collaborators on Apr 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listd: api docsIssues with https://api.flutter.dev/frameworkflutter/packages/flutter repository. See also f: labels.r: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions