AsyncNotifier在我在flutter中使用ref.watch时保持渲染UI。

huangapple go评论59阅读模式
英文:

AsyncNotifier keeps rendering UI when I use it with ref.watch in flutter

问题

build方法中,我初始化返回值的AsyncNotifier。

class ContractConfigViewModel extends AsyncNotifier<ContractConfigModel> {
  late final AuthenticationRepository _authRepository;

  @override
  FutureOr<ContractConfigModel> build() async {
    _authRepository = ref.read(authRepo);

    final userId = _authRepository.user!.uid;

    final adminData = await _authRepository.getAdminProfile(userId);
    final adminProfile = AdminProfileModel.fromJson(adminData!);
    if (!adminProfile.master) {
      return ContractConfigModel(
          contractType: adminProfile.contractType,
          contractName: "${adminProfile.region} ${adminProfile.smallRegion}");
    }
    return ContractConfigModel(
      contractType: adminProfile.contractType,
      contractName: adminProfile.region,
    );
  }

  void setContractType(String value) {
    state = const AsyncValue.loading();
    final contractModel = ContractConfigModel(
      contractType: value,
      contractName: state.value!.contractName,
    );
    state = AsyncValue.data(contractModel);
  }

  void setContractName(String value) {
    state = const AsyncValue.loading();
    final contractModel = ContractConfigModel(
      contractType: state.value!.contractType,
      contractName: value,
    );
    state = AsyncValue.data(contractModel);
  }
}

这里的getAdminProfile函数是用于从Firestore获取数据的函数。

Future<Map<String, dynamic>?> getAdminProfile(String uid) async {
    final doc = await _db.collection("admin").doc(uid).get();
    return doc.data()!;
}

我需要在UI中使用ContractConfigModel的值。所以,当我从ConsumerStatefulWidget返回UI时,我使用ref.watch函数来更新UI,每当ContractConfigModel的值被更新时。

@override
Widget build(BuildContext context) {
    return ref.watch(contractConfigProvider).when(
          data: (data) {
            final userContractType = data.contractType;
            final userContractName = data.contractName;
            print(userContractName);

            return FutureBuilder(
            // ...
            );
          },
          // ...
    );
}

但是,当我打印从ref.watch(contractConfigProvider)获取的数据时,即使ContractConfigModel的值没有被更新,它仍然会持续打印值。所以,即使我在这个组件中更新了一些内容,它也会被覆盖。

是什么原因导致contractConfigProvider持续运行在这里?

请帮助我。

此外,我收到以下错误消息:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following FirebaseException was thrown building DefaultSelectionStyle:
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
The relevant error-causing widget was:
  MaterialApp
MaterialApp:file:///Users/hayat/FlutterProjects/ProjectsFiles/onldocc_admin/lib/main.dart:47:24
main.dart:47
When the exception was thrown, this was the stack:
#1      <anonymous closure> (http://localhost:50230/packages/riverpod/src/stack_trace.dart:9:11)
#2      when (http://localhost:50230/packages/riverpod/src/result.dart:110:17)
#3      get requireState (http://localhost:50230/packages/riverpod/src/framework/element.dart:200:17)
#4      read (http://localhost:50230/packages/riverpod/src/framework/provider_base.dart:106:19)
#5      read (http://localhost:50230/packages/riverpod/src/framework/container.dart:229:20)
#6      read (http://localhost:50230/packages/riverpod/src/framework/element.dart:691:23)
#7      <anonymous closure> (http://localhost:50230/packages/onldocc_admin/router.dart:19:31)
#8      processRedirect (http://localhost:50230/packages/go_router/src/configuration.dart:432:62)
#9      redirect (http://localhost:50230/packages/go_router/src/configuration.dart:444:14)
#10     [_redirect] (http://localhost:50230/packages/go_router/src/parser.dart:149:10)
...

这个错误是因为没有创建Firebase App,需要调用Firebase.initializeApp()来创建Firebase App。

英文:

I have AsyncNotifier and in build method, I initialize return value.

class ContractConfigViewModel extends AsyncNotifier&lt;ContractConfigModel&gt; {
  late final AuthenticationRepository _authRepository;

  @override
  FutureOr&lt;ContractConfigModel&gt; build() async {
    _authRepository = ref.read(authRepo);

    final userId = _authRepository.user!.uid;

    final adminData = await _authRepository.getAdminProfile(userId);
    final adminProfile = AdminProfileModel.fromJson(adminData!);
    if (!adminProfile.master) {
      return ContractConfigModel(
          contractType: adminProfile.contractType,
          contractName: &quot;${adminProfile.region} ${adminProfile.smallRegion}&quot;);
    }
    return ContractConfigModel(
      contractType: adminProfile.contractType,
      contractName: adminProfile.region,
    );
  }

  void setContractType(String value) {
    state = const AsyncValue.loading();
    final contractModel = ContractConfigModel(
      contractType: value,
      contractName: state.value!.contractName,
    );
    state = AsyncValue.data(contractModel);
  }

  void setContractName(String value) {
    state = const AsyncValue.loading();
    final contractModel = ContractConfigModel(
      contractType: state.value!.contractType,
      contractName: value,
    );
    state = AsyncValue.data(contractModel);
  }
}

final contractConfigProvider =
    AsyncNotifierProvider&lt;ContractConfigViewModel, ContractConfigModel&gt;(
  () =&gt; ContractConfigViewModel(),
);

ContractConfigModel:

class ContractConfigModel {
  String contractType;
  String contractName;

  ContractConfigModel({
    required this.contractType,
    required this.contractName,
  });

  ContractConfigModel.empty()
      : contractType = &quot;&quot;,
        contractName = &quot;;&quot;;
}

Here, getAdminProfile function is function to get data from FireStore.

Future&lt;Map&lt;String, dynamic&gt;?&gt; getAdminProfile(String uid) async {
    final doc = await _db.collection(&quot;admin&quot;).doc(uid).get();
    return doc.data()!;
  }

And I need values of this ContractConfigModel in UI.

So when I return UI from ConsumerStatefulWidget, I use ref.watch function to update UI, whenever this ContractConfigModel value is udpated.

   @override
  Widget build(BuildContext context) {
    return ref.watch(contractConfigProvider).when(
          data: (data) {
            final userContractType = data.contractType;
            final userContractName = data.contractName;
            print(userContractName);

            return FutureBuilder(

.....

But when I print data coming from ref.watch(contractConfigProvider), it keeps printing value permanently even though ContractConfigModel value is not updated.

So even though I update something in this component, It is overwritten.

What causes keeps run contractConfigProvider here?

Please help me..

plus)

I get this error message

  ═╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following FirebaseException was thrown building DefaultSelectionStyle:
[core/no-app] No Firebase App &#39;[DEFAULT]&#39; has been created - call Firebase.initializeApp()
The relevant error-causing widget was:
MaterialApp
MaterialApp:file:///Users/hayat/FlutterProjects/ProjectsFiles/onldocc_admin/lib/main.dart:47:24
main.dart:47
When the exception was thrown, this was the stack:
#1      &lt;anonymous closure&gt; (http://localhost:50230/packages/riverpod/src/stack_trace.dart:9:11)
#2      when (http://localhost:50230/packages/riverpod/src/result.dart:110:17)
#3      get requireState (http://localhost:50230/packages/riverpod/src/framework/element.dart:200:17)
#4      read (http://localhost:50230/packages/riverpod/src/framework/provider_base.dart:106:19)
#5      read (http://localhost:50230/packages/riverpod/src/framework/container.dart:229:20)
#6      read (http://localhost:50230/packages/riverpod/src/framework/element.dart:691:23)
#7      &lt;anonymous closure&gt; (http://localhost:50230/packages/onldocc_admin/router.dart:19:31)
#8      processRedirect (http://localhost:50230/packages/go_router/src/configuration.dart:432:62)
#9      redirect (http://localhost:50230/packages/go_router/src/configuration.dart:444:14)
#10     [_redirect] (http://localhost:50230/packages/go_router/src/parser.dart:149:10)
#11     parseRouteInformationWithDependencies (http://localhost:50230/packages/go_router/src/parser.dart:98:7)
#12     [_processRouteInformation] (http://localhost:50230/packages/flutter/src/widgets/router.dart:730:12)
#13     restoreState (http://localhost:50230/packages/flutter/src/widgets/router.dart:594:7)
#14     [_doRestore] (http://localhost:50230/packages/flutter/src/widgets/restoration.dart:912:5)
#15     didChangeDependencies (http://localhost:50230/packages/flutter/src/widgets/restoration.dart:898:7)
#16     didChangeDependencies (http://localhost:50230/packages/flutter/src/widgets/router.dart:669:11)
#17     [_firstBuild] (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5132:11)
#18     mount (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4957:5)
#19     inflateWidget (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3964:15)
#20     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3695:20)
#21     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#22     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#23     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
#24     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#25     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#26     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#27     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
#28     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#29     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#30     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#31     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
#32     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#33     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#34     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#35     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
#36     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#37     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#38     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#39     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5057:5)
#40     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#41     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#42     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#43     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
#44     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#45     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#46     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#47     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5057:5)
#48     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#49     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#50     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5146:11)
#51     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#52     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5169:5)
#53     updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3679:14)
#54     performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#55     rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#56     update (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5312:5)
....
#693    rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#694    [_firstBuild] (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4963:5)
#695    mount (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4957:5)
#696    inflateWidget (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3964:15)
#697    updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3701:18)
#698    performRebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:5006:16)
#699    rebuild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4701:7)
#700    [_firstBuild] (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4963:5)
#701    mount (http://localhost:50230/packages/flutter/src/widgets/framework.dart:4957:5)
#702    inflateWidget (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3964:15)
#703    updateChild (http://localhost:50230/packages/flutter/src/widgets/framework.dart:3701:18)
#704    [_rebuild] (http://localhost:50230/packages/flutter/src/widgets/binding.dart:1195:16)
#705    mount (http://localhost:50230/packages/flutter/src/widgets/binding.dart:1164:5)
#706    &lt;anonymous closure&gt; (http://localhost:50230/packages/flutter/src/widgets/binding.dart:1111:16)
#707    buildScope (http://localhost:50230/packages/flutter/src/widgets/framework.dart:2713:19)
#708    attachToRenderTree (http://localhost:50230/packages/flutter/src/widgets/binding.dart:1110:12)
#709    attachRootWidget (http://localhost:50230/packages/flutter/src/widgets/binding.dart:943:24)
#710    &lt;anonymous closure&gt; (http://localhost:50230/packages/flutter/src/widgets/binding.dart:924:7)
#711    internalCallback (http://localhost:50230/dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart:48:19)
════════════════════════════════════════════════════════════════════════════════════════════════════

答案1

得分: 0

尝试将你的 ContractConfigModel 设为不可变 —— 所有字段必须为 final,构造函数必须为 const。这样应该能解决你的问题。

另外,考虑使用 freezed 来通过 copyWith 轻松修改你的模型。

英文:

Try making your ContractConfigModel immutable -- all fields must be final and the constructor const. This should solve your issue.

Also, consider using freezed to easily change your model via copyWith.

huangapple
  • 本文由 发表于 2023年7月13日 22:27:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76680514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定