如何控制一个包含来自Firebase Firestore的信息的提供程序,具有多个参数。

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

how to control a provider that contains information coming from firebasefirestore with more than one argument

问题

我是新手使用Flutter,但我正在创建一个应用程序,主要目标是让用户能够筛选食谱。也就是说,在这个应用程序中会有很多食谱,每个食谱都有"时间"、"价格"、"口味"、"卡路里"和"类型"等属性。根据这些值,我进行了Firestore搜索并返回结果。

在这个应用程序中,我将结构组织如下:"Repository"、"Controller"和"Screen"。在"Repository"(用于放置Firebase调用的地方)中,我放置了以下函数:

Stream<List<Receita>> getReceitasRefeicao(
      String tipo, int maxPreco, int minLikes, int maxCalorias) {
    return _receitas
        .where('tipo', isEqualTo: tipo)
        .where('preco', isLessThan: maxPreco)
        .where('likes', isGreaterThanOrEqualTo: minLikes)
        .where('calorias', isGreaterThanOrEqualTo: maxCalorias)
        .snapshots()
        .map(
          (event) => event.docs
              .map((e) => Receita.fromMap(e.data() as Map<String, dynamic>))
              .toList(),
        );
  }

在"Controller"中,我习惯于使用对"Repository"函数的引用,并使用"STREAMPROVIDER"来监听所做的更改,例如:

Stream<List<Receita>> getReceitasRefeicao(
      String tipo, int maxPreco, int minLikes, int maxCalorias) {
        return _receitaRepository.getReceitasRefeicao(tipo,maxPreco,minLikes,maxCalorias);
  }

final getReceitasRefeicaoProvider = StreamProvider.family((ref, String tipo, int maxPreco, int minLikes, int maxCalorias) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(tipo, maxPreco, minLikes, maxCalorias);
});

final receitaControllerProvider =
    StateNotifierProvider<ReceitaController, bool>((ref) {
  final receitaRepository = ref.watch(receitaRepositoryProvider);
  final storageRepository = ref.watch(storageRepositoryProvider);
  return ReceitaController(
      receitaRepository: receitaRepository,
      ref: ref,
      storageRepository: storageRepository);
});

然而,直到现在,在我的应用程序中,我只需要传递一个参数给这些StreamProvider就能满足我的Firebase调用。在这种情况下,我必须传递多个参数,我遇到了一个错误:

参数类型 'Stream<List> Function(StreamProviderRef, String, int, int, int)' 无法分配给参数类型 'Stream Function(StreamProviderRef, dynamic)'。

我不知道现在应该使用什么类型的StreamProvider,我已经搜索过但没有找到任何信息。

我已经有一个可以获取所有食谱的StreamProvider,所以我正在考虑使用那个StreamProvider,并使用一些If语句,但我认为这不是一个好的做法。

英文:

I'm new to flutter, however I'm creating an app where the main objective is for the user to be able to filter the recipes. that is, in this application there will be many recipes and each recipe has a "time" "price" "tastes" "calories" "type". Given these values I do a firestore search and give the results.

In this application I am organizing the structure as follows "Repository" "Controller" and "Screen".
In the repository (place where I put the firebase calls) I put the following function:

Stream&lt;List&lt;Receita&gt;&gt; getReceitasRefeicao(
      String tipo, int maxPreco, int minLikes, int maxCalorias) {
    return _receitas
        .where(&#39;tipo&#39;, isEqualTo: tipo)
        .where(&#39;preco&#39;, isLessThan: maxPreco)
        .where(&#39;likes&#39;, isGreaterThanOrEqualTo: minLikes)
        .where(&#39;calorias&#39;, isGreaterThanOrEqualTo: maxCalorias)
        .snapshots()
        .map(
          (event) =&gt; event.docs
              .map((e) =&gt; Receita.fromMap(e.data() as Map&lt;String, dynamic&gt;))
              .toList(),
        );
  }

In the controller I'm used to using a reference to the repository function and using a STREAMPROVIDER to listen to the changes made, for example:

Stream&lt;List&lt;Receita&gt;&gt; getReceitasRefeicao(
      String tipo, int maxPreco, int minLikes, int maxCalorias) {
            return _receitaRepository.getReceitasRefeicao(tipo,maxPreco,minLikes,maxCalorias);
      }


final getReceitasRefeicaoProvider = StreamProvider.family((ref, String tipo, int maxPreco, int minLikes, int maxCalorias) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(tipo, maxPreco, minLikes, maxCalorias);
});


final receitaControllerProvider =
    StateNotifierProvider&lt;ReceitaController, bool&gt;((ref) {
  final receitaRepository = ref.watch(receitaRepositoryProvider);
  final storageRepository = ref.watch(storageRepositoryProvider);
  return ReceitaController(
      receitaRepository: receitaRepository,
      ref: ref,
      storageRepository: storageRepository);
});

However, until now in my application I only needed to pass an argument to these StreamProviders to fulfill my calls to firebase. In this case I have to pass more than one argument and I got an error:

The argument type 'Stream<List<Receita>> Function(StreamProviderRef<dynamic>, String, int, int, int)' can't be assigned to the parameter type 'Stream<dynamic> Function(StreamProviderRef<dynamic>, dynamic)'.

I don't know what kind of StreamProvider to use now I've already searched but I didn't find anything.

I already have a StreamProvider that gives me all the recipes, so I'm thinking of using that StreamProvider and use some If statements but I don't think it's good practice.

答案1

得分: 2

  1. 检查Riverpod generator

这可以帮助您创建具有family属性和多个参数的自动可处理或不同的提供程序

如何控制一个包含来自Firebase Firestore的信息的提供程序,具有多个参数。

我只是不确定流提供程序是否与riverpod generator一起使用(截至今天,它仍然是一个早期包)。您可以尝试像这样使用它:

@Riverpod(dependencies: [receitaControllerProvider]) ///您的其他提供程序也需要生成,以便在此处传递函数
StreamProvider<List<Receita>> getReceitasRefeicao(getReceitasRefeicaoRef ref, {
  required String tipo,
  required int maxPreco,
  required int minLikes,
  required int maxCalorias,
}){
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(tipo, maxPreco, minLikes, maxCalorias);
}
  1. 现在您可以传递一个记录(如果您使用的是flutter 3.10)

只需创建一个typedef(或者不要,它仍然可以工作,但您必须在提供程序中声明所有记录作为类型,这真的很长)

typedef ReceitasParams = ({String tipo, int maxPreco, int minLikes, int maxCalorias});
    
final getReceitasRefeicaoProvider = StreamProvider.family<List<Receita>, ReceitasParams>((ref, myReceitasParams) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(myReceitasParams.tipo, myReceitasParams.maxPreco, myReceitasParams.minLikes, myReceitasParams.maxCalorias);
});
  1. 传统的不可变类

适用于每个Flutter版本,无需任何包

/// 使用Equatable,Freezed或手动覆盖哈希和相等方法
class ReceitasParams {
  final String tipo;
  final int maxPreco;
  final int minLikes;
  final int maxCalorias;

  const ReceitasParams({
    required this.tipo,
    required this.maxPreco,
    required this.minLikes,
    required this.maxCalorias,
  });

}
final getReceitasRefeicaoProvider = StreamProvider.family<List<Receita>, ReceitasParams>((ref, ReceitasParams params) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(params.tipo, params.maxPreco, params.minLikes, params.maxCalorias);
});
英文:

Yeah family only allows you to pass one argument, there are 3 ways to solve it now:

  1. Check Riverpod generator

This can help you create auto disposable or different providers with family attribute and more than one parameter

如何控制一个包含来自Firebase Firestore的信息的提供程序,具有多个参数。

I'm just not sure if stream provider works with riverpod generator as of today (it's still an early package). You can try it like this:

@Riverpod(dependencies: [receitaControllerProvider]) /// Your other providers will need to be generated too so you pass the function here
StreamProvider&lt;List&lt;Receita&gt;&gt; getReceitasRefeicao(getReceitasRefeicaoRef ref, {
  required String tipo,
  required int maxPreco,
  required int minLikes,
  required int maxCalorias,
}){
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(tipo, maxPreco, minLikes, maxCalorias);
}
  1. You can now pass a Record (If you're using flutter 3.10)

Just create a typedef (or not, it will still work but you'll have to declare all the Record as a type in your provider and its really long)

typedef ReceitasParams = ({String tipo, int maxPreco, int minLikes, int maxCalorias});
    
final getReceitasRefeicaoProvider = StreamProvider.family&lt;List&lt;Receita&gt;, ReceitasParams&gt;((ref, myReceitasParams) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(myReceitasParams.tipo, myReceitasParams.maxPreco, myReceitasParams.minLikes, myReceitasParams.maxCalorias);
});
  1. The ol' reliable immutable class

Works with every Flutter version and no package required

/// Use Equatable, Freezed or override manually the hash and equal methods
class ReceitasParams {
  final String tipo;
  final int maxPreco;
  final int minLikes;
  final int maxCalorias;

  const ReceitasParams({
    required this.tipo,
    required this.maxPreco,
    required this.minLikes,
    required this.maxCalorias,
  });

}
final getReceitasRefeicaoProvider = StreamProvider.family&lt;List&lt;Receita&gt;, ReceitasParams&gt;((ref, ReceitasParams params) {
  final postController = ref.watch(receitaControllerProvider.notifier);
  return postController.getReceitasRefeicao(params.tipo, params.maxPreco, params.minLikes, params.maxCalorias);
});

huangapple
  • 本文由 发表于 2023年6月6日 09:29:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410897.html
匿名

发表评论

匿名网友

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

确定