Провайдер Flutter Прослушивание условия внутри провайдера

У меня есть провайдер со состояниями:

enum RemoteJSONState { parsing, parsed, failedToParse }

В одном из своих виджетов я слушаю все изменения с помощью

class RemoteJSONStateProvider with ChangeNotifier {
  set remoteJSONState(RemoteJSONState givenState) {
    if (givenState == _remoteJSONState) {
      return;
    }

    _remoteJSONState = givenState;
    notifyListeners();
  }
}

В другом моем виджете я хочу слушать только проанализированное состояние. Это связано с тем, что изначально мой виджет обрабатывает информацию на основе локального хранилища. Когда извлекаются удаленные данные, они обновляются полученной информацией. Если загрузка не удалась, я просто не хочу создавать свой виджет и хочу использовать доступную локальную информацию. Следовательно, я не хочу, чтобы виджет перестраивался.

Вот что я пробовал до сих пор.

@override
  Widget build(BuildContext context) {
    RemoteJSONStateProvider =
        Provider.of<RemoteJSONStateProvider>(context);
  }

Проблема в том, что мой виджет перестраивается, если состояние RemoteJSONStateProvider изменяется на failedToParse. Как я могу прислушиваться только к условию? который

RemoteJSONStateProvider._remoteJSONState == RemoteJSONState.parsed

person cs guy    schedule 18.10.2020    source источник


Ответы (4)


Создайте локальную переменную с именем isParsedStateChange, которая будет уведомлять только при вызове проанализированного состояния.

class RemoteJSONStateProvider with ChangeNotifier {
  bool _isParsedStateChange = false;
  get isParsedStateChange => _isParsedStateChange;

  set parsedJSONState(RemoteJSONState givenState) {
    _isParsedStateChange = (RemoteJSONState. parsed == givenState) 
    if(_isParsedStateChange) {
      notifyListeners();
     }
  }
}

Использовать лайк

RemoteJSONStateProvider =
        Provider.of<RemoteJSONStateProvider>(context).isParsedStateChange;

Примечание. Создайте отдельный метод, который будет устанавливать состояние анализа.

person Jitesh Mohite    schedule 18.10.2020
comment
Я хочу сохранить исходную функцию, которую я использую, поскольку от нее зависит другой виджет. Если я сохраню старый метод с этим новым, не будет ли мой виджет перестроен, поскольку старый метод использует notifyListeners ()? - person cs guy; 18.10.2020
comment
этого не должно быть, поскольку вы слушаете переменную. - person Jitesh Mohite; 18.10.2020
comment
другие слушатели все равно будут уведомлены, поскольку notifyListeners (); называется - person cs guy; 18.10.2020

Изменить:

@ jitsm555 на 8 секунд быстрее меня, код лучше.


Вы можете определить другую переменную в поставщике следующим образом:

    bool isParsed = false;

И установите его в свое состояние:

  class RemoteJSONStateProvider with ChangeNotifier {
    set remoteJSONState(RemoteJSONState givenState) {
      if (givenState == _remoteJSONState) {
        isParsed = true;
        return;
      }

      _remoteJSONState = givenState;
      notifyListeners();
    }
  }

После этого можно будет прослушивать только условие isParsed:

   RemoteJSONStateProvider.isParsed
person Akif    schedule 18.10.2020

Другие ответы меня не удовлетворили, поскольку мне нужно сохранить старую функцию для другого моего виджета. После часа исследования я создал виджет «Селектор» для своих нужд.

Selector<RemoteJSONStateProvider, RemoteJSONState>(
      builder: (context, remoteJSONStateProvider, child) {
        print("rebuild");
        return Text('build');
      },
      selector: (buildContext, remoteJSONStateProvider) =>
          remoteJSONStateProvider.remoteJSONState,
      shouldRebuild: (prev, next) =>
          prev != RemoteJSONState.parsed && next == RemoteJSONState.parsed,
    );
person cs guy    schedule 18.10.2020

Вы можете использовать второй класс слоя.

enum RemoteJSONState { parsing, parsed, failedToParse }

class RemoteJSONStateProvider extends ChangeNotifier {
    
    RemoteJSONState _jsonState;
    RemoteJSONState get jsonState => _jsonState; 
    
    RemoteJSONStateProvider();
    RemoteJSONStateProvider.instance();

    remoteJSONState(RemoteJSONState givenState) {
        if (givenState == _remoteJSONState) {
            return;
        }
        _jsonState = givenState;
        notifyListeners();
    }
}


class MyNotifier extends ChangeNotifier {
   RemoteJSONStateProvider _jsonStateProvider;
   RemoteJSONState _jsonState;
   RemoteJSONState get jsonState => _jsonState;
   VoidCallback _jsonStatusListener;

   MyNotifier();
   MyNotifier.instance(BuildContext context){
      _listenJSONState(context);
   }

   _listenJSONState(BuildContext context){
      _jsonStateProvider = Provider.of<RemoteJSONStateProvider>(context, listen: false);
      _jsonStatusListener = (){
         if(_jsonStateProvider.jsonState == RemoteJSONState.parsed){
            _jsonState == RemoteJSONState.parsed;
            notifyListeners();
         }
      };
      _jsonStateProvider.addListener(_jsonStatusListener);
   }

   parseJSON(RemoteJSONState state){
       _jsonStateProvider.remoteJSONState(state);
   }
}

class YourWidget extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return ChangeNotifierProvider(
        create: (context) => MyNotifier.instance(context),
            child: Consumer<MyNotifier>(
                builder: (context, myNotifierModel, child) {
                    return myNotifierModel.jsonState == null 
                    ? FlatButton(
                        child: Text("parse json"),
                        onPressed: (){
                            myNotifierModel.parseJSON(RemoteJSONState.parsed);
                        }
                    )
                    : Container(
                        child: myNotifierModel.jsonState == RemoteJSONState.parsing ?
                        Text("JSON PARSING") : 
                        Text("JSON PARSED")                        
                    );
                },
            ),
        );
    }
}
person blokberg    schedule 18.10.2020