首页 > 解决方案 > Flutter 在不使用 context.read() 的情况下调用 Riverpod 函数

问题描述

默认情况下,在定义Riverpod提供者后,我们可以单击任何小部件来调用某些方法,例如从 Web 服务或其他东西获取数据。

例如:

context.read(washingServiceProvider.notifier).getService;

现在我的问题是如何getService在不点击任何小部件的情况下调用它?当我尝试使用此代码时:

class GetServices extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final washing = useProvider(washingServiceProvider.notifier);
    washing.getService();

    return Scaffold();
 ...
}

我收到此错误:

E/flutter ( 3398): [ERROR:flutter/shell/common/shell.cc(103)] Dart Unhandled Exception: setState() or markNeedsBuild() called during build.
E/flutter ( 3398): This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
E/flutter ( 3398): The widget on which setState() or markNeedsBuild() was called was:
E/flutter ( 3398):   UncontrolledProviderScope
E/flutter ( 3398): The widget which was currently being built when the offending call was made was:
E/flutter ( 3398):   GetServices, stack trace: #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4217:11)
E/flutter ( 3398): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4232:6)
E/flutter ( 3398): #2      ProviderElement._debugMarkWillChange.<anonymous closure> (package:riverpod/src/framework/base_provider.dart:660:16)
E/flutter ( 3398): #3      ProviderElement._debugMarkWillChange (package:riverpod/src/framework/base_provider.dart:664:6)
E/flutter ( 3398): #4      ProviderStateBase.exposedValue=.<anonymous closure> (package:riverpod/src/framework/base_provider.dart:900:16)
E/flutter ( 3398): #5      ProviderStateBase.exposedValue= (package:riverpod/src/framework/base_provider.dart:902:6)
E/flutter ( 3398): #6      _StateNotifierProviderState._listener (package:riverpod/src/state_notifier_provider.dart:92:5)
E/flutter ( 3398): #7      StateNotifier.state= (package:state_notifier/state_notifier.dart:162:31)
E/flutter ( 3398): #8      RequestStateNotifier.makeRequest (package:washing_app/core/service/network/request_state_notifier.dart:10:7)
E/flutter ( 3398): #9      WashingRequestNotifier.getService (package:washing_app/src/screens/dashboard/tabs/category_products/repository/washing_service_repository.dart:98:7)
E/flutter ( 3398): #10     GetServices.build (package:washing_app/src/screens/dashboard/get_services.dart:39:13)
E/flutter ( 3398): #11     StatelessElement.build (package:flutter/src/widgets/framework.dart:4648:28)
E/flutter ( 3398): #12     HookElement.build (package:flutter_hooks/src/framework.dart:417:27)
E/flutter ( 3398): #13     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4574:15)
E/flutter ( 3398): #14     Element.rebuild (package:flutter/src/widgets/framework.dart:4267:5)
E/flutter ( 3398): #15     StatelessElement.update (package:flutter/src/widgets/framework.dart:4655:5)
E/flutter ( 3398): #16     HookElement.update (package:flutter_hooks/src/framework.dart:379:11)
E/flutter ( 3398): #17     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #18     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4599:16)
E/flutter ( 3398): #19     Element.rebuild (package:flutter/src/widgets/framework.dart:4267:5)
E/flutter ( 3398): #20     StatelessElement.update (package:flutter/src/widgets/framework.dart:4655:5)
E/flutter ( 3398): #21     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #22     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6090:14)
E/flutter ( 3398): #23     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4599:16)
E/flutter ( 3398): #25     Element.rebuild (package:flutter/src/widgets/framework.dart:4267:5)
E/flutter ( 3398): #26     StatelessElement.update (package:flutter/src/widgets/framework.dart:4655:5)
E/flutter ( 3398): #27     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #28     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6090:14)
E/flutter ( 3398): #29     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #30     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6090:14)
E/flutter ( 3398): #31     Element.updateChild (package:flutter/src/widgets/framework.dart:3350:15)
E/flutter ( 3398): #32     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4599:16)
E/flutter ( 3398): #33     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4746:11)
E/flutter ( 3398): #34     Element.rebuild (package:flutter/src/widgets/framework.dart:4267:5)
E/flutter ( 3398): #35     StatefulElement.up
E/flutter ( 3398): [ERROR:flutter/shell/common/shell.cc(103)] Dart Unhandled Exception: setState() or markNeedsBuild() called during build.

E/flutter ( 3398): This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

我定义的提供者:

final washingServicesRepositoryProvider = Provider((ref) => WashingServiceRepository(ref.read));
final washingServiceProvider =
    StateNotifierProvider<WashingRequestNotifier, NetworkRequestState<WashingServicesResponseStructure>>(
        (ref) => WashingRequestNotifier(ref.watch(washingServicesRepositoryProvider)));

class WashingServiceRepository {
  final Reader _reader;

  WashingServiceRepository(this._reader);

  Future<WashingServicesResponseStructure> getService() async {
    try {
      const _r = RetryOptions(maxAttempts: 3);
      final _res = await _r.retry(() => _reader(dioProvider)
          .post(
            Server.$getData,
            options: Options(
              headers: {'Content-Type': 'application/json'},
            ),
          )
          ..timeout(const Duration(seconds: 30)),
          retryIf: (e) => e is SocketException || e is TimeoutException);

      return WashingServicesResponseStructure.fromJson(_res.data as Map<String, dynamic>);
    } on DioError catch (error) {
      rethrow;
    }
  }

}

class WashingRequestNotifier extends RequestStateNotifier<WashingServicesResponseStructure> {
  final WashingServiceRepository _washingServiceRepository;

  WashingRequestNotifier(this._washingServiceRepository);

  Future<NetworkRequestState<WashingServicesResponseStructure>> getService() =>
      makeRequest(() => _washingServiceRepository.getService());
}

标签: flutterdartriverpodhook-widgets

解决方案


推荐阅读