7

有没有办法访问提供的“ .family”更改通知器的实例(已经实例化,传递正确的参数)而无需再次传递参数?

在供应商

当您创建 ChangeNotifier 的提供者(需要参数)时,您可以获得与它提供的相同的更改通知Provider.of<ChangeNotif>(context)

class ChangeNotif extends ChangeNotifier {
  final String id;
  const ChangeNotif(this.id);
}

ChangeNotifierProvider(create: (_) => ChangeNotif("dash"));

使用正确的参数创建提供程序后,您可以在该小部件树的任何位置获取它提供的任何内容,而无需任何语法,例如Provider.of<ChangeNotif("dash")>(context)but Provider.of<ChangeNotif>(context)

在河边

由于在获取它的实例时必须将参数传递给提供者,因此我必须将提供者分配给一个变量,以便将其传递给需要提供者提供的更改通知器的子代。

final changeNotifProvider = ChangeNotifierProvider.family<ChangeNotif, String>((ref, id) => ChangeNotif(id));

class A extends HookWidget {
  build() {
    final _changeNotifProvider = changeNotifProvider("dash");
    final _changeNotif = useProvider(_changeNotifProvider);

    return Column(
     children: [
       B(),
       c(_changeNotifProvider),
     ]
    );
  }
}

有没有办法在_changeNotif不将其作为参数传递给子小部件的情况下获得实例化?有什么方法可以在另一个不是 A 子级的小部件中获取相同的 _changeNotif 实例(例如Provider.of<ChangeNotif>(context)在 Provider 中使用而无需传递新参数)?

4

2 回答 2

1

我使用此扩展来获取实例的所有StateNotifierProviderFamily实例,但您也可以为ChangeNotifierProviderFamily. 您确实需要在提供程序中注册它们:

extension StateNotifierProviderFamilyExtension<
    Notifier extends StateNotifier<Value>,
    Value,
    Param> on StateNotifierProviderFamily<Notifier, Value, Param> {
  /// Get all the registered versions of this `StateNotifierProviderFamily`
  ///
  /// This function requires a reader to the current `ProviderScope` to
  /// get the `familyKeysStorageProvider`
  ///
  /// The family needs to be registered with the `familyKeysStorageProvider`,
  /// like this:
  ///
  /// ```dart
  /// final keyStorage = ref.read(familyKeysStorageProvider(myProvider));
  /// keyStorage.state.add(myKey);
  /// ```
  Iterable<T> all<T extends StateNotifierProvider<Notifier, Value>>(
      Reader read) {
    return read(_familyKeysStorageProvider(this))
        .state
        .map((key) => call(key) as T);
  }

  Set<dynamic> keys(Reader read) =>
      read(_familyKeysStorageProvider(this)).state;
  void addKey(Reader read, dynamic key) => this.keys(read).add(key);
}

/// Use this provider to register keys for a `StateNotifierProviderFamily`
/// object.
///
/// After registration of the keys, it is possible to retrieve all registered
/// instances with the `all(Reader read)` method on `StateNotifierProviderFamily`
final _familyKeysStorageProvider =
    StateProvider.family<Set<dynamic>, StateNotifierProviderFamily>((ref, key) {
  return {};
});

你可以这样注册:

final myStateProvider = StateNotifierProvider.family<
    MyStateNotifier,
    MyState,
    MyKey>(
  (ref, key) {
    myStateProvider.addKey(ref.read, key);
    return MyStateNotifier(ref.read, key);
  },
);

当然,您还需要导入扩展才能使其正常工作。

对于ChangeNotifierProviderFamily我认为它会是这样的(我没有测试过):

extension ChangeNotifierProviderFamilyExtension<Notifier extends ChangeNotifier,
    Param> on ChangeNotifierProviderFamily<Notifier, Param> {
  Iterable<T> all<T extends ChangeNotifierProvider<Notifier>>(Reader read) {
    return read(_notifierFamilyKeysStorageProvider(this))
        .state
        .map((key) => call(key) as T);
  }

  Set<dynamic> keys(Reader read) =>
      read(_notifierFamilyKeysStorageProvider(this)).state;
  void addKey(Reader read, dynamic key) => this.keys(read).add(key);
}

final _notifierFamilyKeysStorageProvider =
    StateProvider.family<Set<dynamic>, ChangeNotifierProviderFamily>(
        (ref, key) {
  return {};
});
于 2021-06-23T07:36:14.763 回答
-2

查看 Riverpod 示例,了解它如何解决该问题Marvel 示例

使用riverpo family vs Provider package的优势在于provider不允许你在widget树下读取同一个类的多个实例,riverpod family没有这个限制

在提供者

MultiProvider(
   providers: [
      ChangeNotifierProvider<ChangeNotif>(
        create: (_) => ChangeNotif('dash')
      ),
      ChangeNotifierProvider<ChangeNotif>(
        create: (_) => ChangeNotif('dash2')
      ),
    // and many more of the same provider but different initial value
   ].
   child: MyWidget()
);

然后在MyWidget做的时候Provider.of<ChangeNotif>(context)你只得到 MultiProvider 创建的最后一个,不能区分相同类型的多个提供者,现在在riverpod 中的一个解决方案和传递家庭的方法是使用具有初始值的ScopedProvider。

final _idProvider = ScopedProvider<String>(null);

class A extends HookWidget {

  @override
  Widget build() {
    final _changeNotif = useProvider(changeNotifProvider("dash"));

    return ProviderScope(
      overrides: [
         _idProvider .overrideWithValue("dash"),
      ],
      child: Column(
        children: [
          B(),
          c(),
        ]
      )
    );
  }
}

现在所有小部件(B 和 C)都可以读取用于创建族的参数,如果提供者已经存在,它将检索它而不重新创建它

class A extends HookWidget {

  @override
  Widget build() {
    final id = useProvider(_idProvider);
    final _changeNotif = useProvider(changeNotifProvider(id)); //the ProviderContainer will check if there is already a family with that id and retrieve it

    return Text(_changeNotif.id);
  }
}
于 2020-11-20T20:41:26.113 回答